zoukankan      html  css  js  c++  java
  • FFmpeg Programming Interface (API) Guide for Beginners

    I. Building FFmpeg in Ubuntu

    Add environment variable

    export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH
    export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH

     or

    echo "export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH">> ~/.bashrc
    echo "export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH">> ~/.bashrc
    source ~/.bashrc

    or

    #echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/dong/2019-nCoV/_install/lib">> ~/.bashrc
    #echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/dong/2019-nCoV/_install/lib/pkgconfig">> ~/.bashrc
    #source ~/.bashrc

    FFmpeg build

    build.sh

    export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH
    export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH
    ./configure --prefix=/home/dong/2019-nCoV/_install --disable-x86asm
    make
    make install

    ffmpeg + x264

    # ffmpeg + x264
    
    echo "export LD_LIBRARY_PATH=/home/zhoudd/ffmpeg/_install/lib:$LD_LIBRARY_PATH">> ~/.bashrc
    echo "export PKG_CONFIG_PATH=/home/zhoudd/ffmpeg/_install/lib/pkgconfig:$PKG_CONFIG_PATH">> ~/.bashrc
    
    source ~/.bashrc
    
    # ffmpeg
    ./configure --prefix=/home/zhoudd/ffmpeg/_install --enable-shared --enable-static --enable-pic
    
    # x264
    ./configure --prefix=/home/zhoudd/ffmpeg/_install --enable-libx264 --enable-gpl --extra-cflags=-I/home/zhoudd/ffmpeg/_install/include --extra-cxxflags=-I/home/zhoudd/ffmpeg/_install/include --extra-ldflags=-L/home/zhoudd/ffmpeg/_install/lib
    
    # build
    gcc muxing.c -o muxing `pkg-config --cflags --libs libavdevice libavformat libavfilter libavcodec libswresample libswscale libavutil` -lx264

    Makefile

    #!/bin/sh
    
    APP = muxing
    
    INCLUDE = 
    -I ../bin/include 
    
    LIB = 
    -L ../bin/lib
    
    SRC = muxing.c
    
    CFLAGS = -g -O0 -lstdc++
    
    LDFLAGS = -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lm -pthread -ldl -lz -lx264
    
    out: 
        gcc $(SRC) -o $(APP) $(LIB) $(INCLUDE) $(CFLAGS) $(LDFLAGS)
    
    clean:
        rm muxing

    FFmpeg + Third party Libraries

    dong@ubuntu:~/2019-nCoV$ tree
    .
    ├── build_centos.sh
    ├── build_ubuntu.sh
    ├── fdk-aac-2.0.0.tar.gz
    ├── ffmpeg-4.1.tar.bz2
    ├── ffmpeg-4.2.2.tar.bz2
    ├── lame-3.100.tar.gz
    ├── last_x264.tar.bz2
    ├── libogg-1.3.4.tar.gz
    ├── libvorbis-1.3.6.tar.gz
    ├── libvpx-1.8.0.tar.gz
    ├── opencore-amr-0.1.3.tar.gz
    ├── openssl-1.1.0f.tar.gz
    ├── SDL-1.2.15.tar.gz
    ├── SDL2-2.0.10.tar.gz
    ├── x265_2.9.tar.gz
    └── xvidcore_1.3.3.orig.tar.gz

    0 directories, 20 files
    dong@ubuntu:~/2019-nCoV$

    build_ubuntu.sh

    #export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH
    #export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH
    
    #echo "export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH">> ~/.bashrc
    #echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/dong/2019-nCoV/_install/lib">> ~/.bashrc
    #echo "export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH">> ~/.bashrc
    #echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/dong/2019-nCoV/_install/lib/pkgconfig">> ~/.bashrc
    
    #source ~/.bashrc
    
    #sudo apt-get install yasm nasm cmake libx11-dev
    
    #1
    tar xvf yasm-1.2.0.tar.gz
    cd yasm-1.2.0
    ./configure #--prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #2
    tar xvf nasm-2.13.03.tar.gz
    cd nasm-2.13.03
    ./configure #--prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #3
    tar xvf zlib-1.2.11.tar.gz
    cd zlib-1.2.11
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared #--enable-static
    make && make install
    cd ..
    
    #4
    tar xvf last_x264.tar.bz2
    cd x264-snapshot-20190512-2245
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static --enable-pic #--disable-asm
    make && make install
    cd ..
    
    #5
    tar xvf x265_2.9.tar.gz
    cd x265_2.9/build/linux
    cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="/home/dong/2019-nCoV/_install" -DENABLE_SHARED:bool=on ../../source
    make
    make install
    cd ../../..
    
    #6
    tar xvf libvpx-1.8.0.tar.gz
    cd libvpx-1.8.0
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #7
    tar xvf fdk-aac-2.0.0.tar.gz
    cd fdk-aac-2.0.0
    ./configure prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #8
    tar xvf xvidcore_1.3.3.orig.tar.gz
    cd xvidcore-1.3.3/build/generic
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ../../..
    
    #9
    tar xvf libogg-1.3.4.tar.gz
    cd libogg-1.3.4
    ./configure prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #10
    tar xvf libvorbis-1.3.6.tar.gz
    cd libvorbis-1.3.6
    ./configure prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #11
    tar xvf lame-3.100.tar.gz
    cd lame-3.100
    ./configure prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #12
    tar xvf opencore-amr-0.1.3.tar.gz
    cd opencore-amr-0.1.3
    ./configure prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #13
    tar xvf SDL-1.2.15.tar.gz
    cd SDL-1.2.15
    sed -e '/_XData32/s:register long:register _Xconst long:' -i src/video/x11/SDL_x11sym.h
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --disable-static
    make && make install
    cd ..
    
    #14
    tar xvf SDL2-2.0.10.tar.gz
    cd SDL2-2.0.10
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make && make install
    cd ..
    
    #15
    tar xvf ffmpeg-4.1.tar.bz2
    cd ffmpeg-4.1
    ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static --enable-ffplay --enable-libx264 --enable-libx265 --enable-gpl --enable-libxvid --enable-libvpx --enable-libvorbis --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-version3 --enable-libfdk-aac --enable-nonfree --enable-postproc --enable-libxcb --disable-vaapi --extra-cflags=-I/home/dong/2019-nCoV/_install/include --extra-cxxflags=-I/home/dong/2019-nCoV/_install/include --extra-ldflags=-L/home/dong/2019-nCoV/_install/lib #
    make && make install
    cd ..

    build_centos.sh

    #export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH
    #export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH
    
    #echo "export LD_LIBRARY_PATH=/home/dong/2019-nCoV/_install/lib:$LD_LIBRARY_PATH">> ~/.bashrc
    #echo "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/home/dong/2019-nCoV/_install/lib">> ~/.bashrc
    #echo "export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH">> ~/.bashrc
    #echo "export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/home/dong/2019-nCoV/_install/lib/pkgconfig">> ~/.bashrc
    
    #source ~/.bashrc
    
    yum install libatomic.x86_64
    yum install libxcb*
    yum install cmake
    
    #1
    tar xvf yasm-1.2.0.tar.gz
    cd yasm-1.2.0
    ./configure #--prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make 
    sudo make install
    cd ..
    
    #2
    tar xvf nasm-2.13.03.tar.gz
    cd nasm-2.13.03
    ./configure #--prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static
    make 
    sudo make install
    cd ..
    
    #3
    tar xvf zlib-1.2.11.tar.gz
    cd zlib-1.2.11
    ./configure --prefix=/usr/local/ffmpeg --enable-shared #--enable-static
    make && make install
    cd ..
    
    #4
    tar xvf last_x264.tar.bz2
    cd x264-snapshot-20190512-2245./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static --enable-pic #--disable-asm
    make && make install
    cd ..
    
    #5
    tar xvf x265_2.9.tar.gz
    cd x265_2.9/build/linux
    cmake -G "Unix Makefiles" -DCMAKE_INSTALL_PREFIX="/home/dong/2019-nCoV/_install" -DENABLE_SHARED:bool=on ../../source
    make
    make install
    cd ../../..
    
    
    #6
    tar xvf libvpx-1.8.0.tar.gz
    cd libvpx-1.8.0
    ./configure --prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #7
    tar xvf fdk-aac-2.0.0.tar.gz
    cd fdk-aac-2.0.0
    ./configure prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #8
    tar xvf xvidcore_1.3.3.orig.tar.gz
    cd xvidcore-1.3.3/build/generic
    ./configure --prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ../../..
    
    #9
    tar xvf libogg-1.3.4.tar.gz
    cd libogg-1.3.4
    ./configure prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #10
    tar xvf libvorbis-1.3.6.tar.gz
    cd libvorbis-1.3.6
    ./configure prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #11
    tar xvf lame-3.100.tar.gz
    cd lame-3.100
    ./configure prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #12
    tar xvf opencore-amr-0.1.3.tar.gz
    cd opencore-amr-0.1.3
    ./configure prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #13
    tar xvf SDL-1.2.15.tar.gz
    cd SDL-1.2.15
    sed -e '/_XData32/s:register long:register _Xconst long:' -i src/video/x11/SDL_x11sym.h
    ./configure --prefix=/usr/local/ffmpeg --enable-shared --disable-static
    make && make install
    cd ..
    
    #14
    tar xvf SDL2-2.0.10.tar.gz
    cd SDL2-2.0.10
    ./configure --prefix=/usr/local/ffmpeg --enable-shared --enable-static
    make && make install
    cd ..
    
    #15
    tar xvf ffmpeg-4.1.tar.bz2
    cd ffmpeg-4.1
    ./configure --prefix=/usr/local/ffmpeg --enable-shared --enable-static --enable-ffplay --enable-libx264 --enable-libx265 --enable-gpl --enable-libxvid --enable-libvpx --enable-libvorbis --enable-libmp3lame --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-version3 --enable-libfdk-aac --enable-nonfree --enable-postproc --enable-libxcb --disable-vaapi --extra-cflags=-I/usr/local/ffmpeg/include --extra-cxxflags=-I/usr/local/ffmpeg/include --extra-ldflags=-L/usr/local/ffmpeg/lib
    make && make install
    cd ..

    II. FFmpeg Example

    dong@ubuntu:~/2019-nCoV/ffmpeg-4.1

    make examples

    dong@ubuntu:~/2019-nCoV/ffmpeg-4.1/doc/examples$ tree
    .
    ├── avio_dir_cmd.c
    ├── avio_reading.c
    ├── decode_audio.c
    ├── decode_video.c
    ├── demuxing_decoding.c
    ├── encode_audio.c
    ├── encode_video.c
    ├── extract_mvs.c
    ├── filter_audio.c
    ├── filtering_audio.c
    ├── filtering_video.c
    ├── http_multiclient.c
    ├── hw_decode.c
    ├── Makefile
    ├── Makefile.example
    ├── metadata.c
    ├── muxing.c
    ├── qsvdec.c
    ├── README
    ├── remuxing.c
    ├── resampling_audio.c
    ├── scaling_video.c
    ├── transcode_aac.c
    ├── transcoding.c
    ├── vaapi_encode.c
    └── vaapi_transcode.c

    0 directories, 26 files

    1. avio

    1.0 Custom AVIOContext

    ffmpeg-4.1/doc/examples/avio_reading.c

    /*
     * Copyright (c) 2014 Stefano Sabatini
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
    /**
     * @file
     * libavformat AVIOContext API example.
     *
     * Make libavformat demuxer access media content through a custom
     * AVIOContext read callback.
     * @example avio_reading.c
     */
    
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavformat/avio.h>
    #include <libavutil/file.h>
    
    struct buffer_data {
        uint8_t *ptr;
        size_t size; ///< size left in the buffer
    };
    
    static int read_packet(void *opaque, uint8_t *buf, int buf_size)
    {
        struct buffer_data *bd = (struct buffer_data *)opaque;
        buf_size = FFMIN(buf_size, bd->size);
    
        if (!buf_size)
            return AVERROR_EOF;
        printf("ptr:%p size:%zu
    ", bd->ptr, bd->size);
    
        /* copy internal buffer data to buf */
        memcpy(buf, bd->ptr, buf_size);
        bd->ptr  += buf_size;
        bd->size -= buf_size;
    
        return buf_size;
    }
    
    int main(int argc, char *argv[])
    {
        AVFormatContext *fmt_ctx = NULL;
        AVIOContext *avio_ctx = NULL;
        uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
        size_t buffer_size, avio_ctx_buffer_size = 4096;
        char *input_filename = NULL;
        int ret = 0;
        struct buffer_data bd = { 0 };
    
        if (argc != 2) {
            fprintf(stderr, "usage: %s input_file
    "
                    "API example program to show how to read from a custom buffer "
                    "accessed through AVIOContext.
    ", argv[0]);
            return 1;
        }
        input_filename = argv[1];
    
        /* slurp file content into buffer */
        ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
        if (ret < 0)
            goto end;
    
        /* fill opaque structure used by the AVIOContext read callback */
        bd.ptr  = buffer;
        bd.size = buffer_size;
    
        if (!(fmt_ctx = avformat_alloc_context())) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
    
        avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
        if (!avio_ctx_buffer) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
        avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                      0, &bd, &read_packet, NULL, NULL);
        if (!avio_ctx) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
        fmt_ctx->pb = avio_ctx;
    
        ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
        if (ret < 0) {
            fprintf(stderr, "Could not open input
    ");
            goto end;
        }
    
        ret = avformat_find_stream_info(fmt_ctx, NULL);
        if (ret < 0) {
            fprintf(stderr, "Could not find stream information
    ");
            goto end;
        }
    
        av_dump_format(fmt_ctx, 0, input_filename, 0);
    
    end:
        avformat_close_input(&fmt_ctx);
        /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
        if (avio_ctx) {
            av_freep(&avio_ctx->buffer);
            av_freep(&avio_ctx);
        }
        av_file_unmap(buffer, buffer_size);
    
        if (ret < 0) {
            fprintf(stderr, "Error occurred: %s
    ", av_err2str(ret));
            return 1;
        }
    
        return 0;
    }

    build.sh

    export LD_LIBRARY_PATH=$(pwd)/_install/lib:$LD_LIBRARY_PATH
    
    #gcc -o transcoding transcoding.c 
    gcc -o muxing muxing.c 
    -I $(pwd) 
    -I $(pwd)/_install/include 
    -I $(pwd)/_install/include/libavcodec 
    -I $(pwd)/_install/include/libavdevice 
    -I $(pwd)/_install/include/libavfilter 
    -I $(pwd)/_install/include/libavformat 
    -I $(pwd)/_install/include/libavutil 
    -I $(pwd)/_install/include/libpostproc 
    -I $(pwd)/_install/include/libswresample 
    -I $(pwd)/_install/include/libswscale 
    -I $(pwd)/_install/include/libpostproc 
    -I $(pwd)/_install/include/libyasm 
    -I $(pwd)/_install/include/SDL 
    -I $(pwd)/_install/include/SDL2 
    -L $(pwd)/_install/lib 
    -Wno-deprecated-declarations -lx264 -lx265 -lSDL -lSDL2 -lavformat -lavutil -lavdevice -lavcodec -lswresample -lavfilter -lswscale -lpostproc -lz -lm -lpthread

    dong@ubuntu:~/ffmpeg/example$ export LD_LIBRARY_PATH=$(pwd)/_install/lib:$LD_LIBRARY_PATH
    dong@ubuntu:~/ffmpeg/example$ ./build.sh
    dong@ubuntu:~/ffmpeg/example$ ls
    avio_reading  avio_reading.c  build.sh  _install  source.200kbps.768x320.flv
    dong@ubuntu:~/ffmpeg/example$ ./avio_reading source.200kbps.768x320.flv
    ptr:0x7f59276ec000 size:6636853
    ptr:0x7f59276ed000 size:6632757
    ptr:0x7f59276ee000 size:6628661
    ptr:0x7f59276ef000 size:6624565
    ptr:0x7f59276f0000 size:6620469
    ptr:0x7f59276f1000 size:6616373
    ptr:0x7f59276f2000 size:6612277
    ptr:0x7f59276f3000 size:6608181
    Input #0, flv, from 'source.200kbps.768x320.flv':
      Metadata:
        major_brand     : isom
        minor_version   : 512
        compatible_brands: isomiso2avc1mp41
        encoder         : Lavf54.63.104
      Duration: 00:03:30.73, start: 0.034000, bitrate: N/A
        Stream #0:0: Video: h264 (High), yuv420p(progressive), 768x320 [SAR 1:1 DAR 12:5], 212 kb/s, 25 fps, 25 tbr, 1k tbn, 50 tbc
        Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 30 kb/s
    dong@ubuntu:~/ffmpeg/example$

    1.1 Custom AVIOContext vs File as Input Source

    /*
     * Copyright (c) 2014 Stefano Sabatini
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
    /**
     * @file
     * libavformat AVIOContext API example.
     *
     * Make libavformat demuxer access media content through a custom
     * AVIOContext read callback.
     * @example avio_reading.c
     */
    
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavformat/avio.h>
    #include <libavutil/file.h>
    
    #define Custom_AVIOContext (0)
    
    #if Custom_AVIOContext
    struct buffer_data {
        uint8_t *ptr;
        size_t size; ///< size left in the buffer
    };
    
    static int read_packet(void *opaque, uint8_t *buf, int buf_size)
    {
        struct buffer_data *bd = (struct buffer_data *)opaque;
        buf_size = FFMIN(buf_size, bd->size);
    
        if (!buf_size)
            return AVERROR_EOF;
        printf("ptr:%p size:%zu
    ", bd->ptr, bd->size);
    
        /* copy internal buffer data to buf */
        memcpy(buf, bd->ptr, buf_size);
        bd->ptr  += buf_size;
        bd->size -= buf_size;
    
        return buf_size;
    }
    #endif
    
    int main(int argc, char *argv[])
    {
        AVFormatContext *fmt_ctx = NULL;
        char *input_filename = argv[1];
        int ret = 0;
    
        if (argc != 2) {
            fprintf(stderr, "usage: %s input_file
    "
                    "API example program to show how to read from a custom buffer "
                    "accessed through AVIOContext.
    ", argv[0]);
            return 1;
        }
    
    #if Custom_AVIOContext
        AVIOContext *avio_ctx = NULL;
        uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
        size_t buffer_size, avio_ctx_buffer_size = 4096;      
        struct buffer_data bd = { 0 };
    
        /* slurp file content into buffer */
        ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
        if (ret < 0)
            goto end;
    
        /* fill opaque structure used by the AVIOContext read callback */
        bd.ptr  = buffer;
        bd.size = buffer_size;
    
        if (!(fmt_ctx = avformat_alloc_context())) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
    
        avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
        if (!avio_ctx_buffer) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
        avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                      0, &bd, &read_packet, NULL, NULL);
        if (!avio_ctx) {
            ret = AVERROR(ENOMEM);
            goto end;
        }
        fmt_ctx->pb = avio_ctx;
    
    
        ret = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    #else
        ret = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);
    #endif
        if (ret < 0) {
            fprintf(stderr, "Could not open input
    ");
            goto end;
        }
    
        ret = avformat_find_stream_info(fmt_ctx, NULL);
        if (ret < 0) {
            fprintf(stderr, "Could not find stream information
    ");
            goto end;
        }
    
        av_dump_format(fmt_ctx, 0, input_filename, 0);
    
    end:
        avformat_close_input(&fmt_ctx);
    
    #if Custom_AVIOContext
        /* note: the internal buffer could have changed, and be != avio_ctx_buffer */
        if (avio_ctx) {
            av_freep(&avio_ctx->buffer);
            av_freep(&avio_ctx);
        }
        av_file_unmap(buffer, buffer_size);
    #endif
    
        if (ret < 0) {
            fprintf(stderr, "Error occurred: %s
    ", av_err2str(ret));
            return 1;
        }
    
        return 0;
    }

    2. encode

    ffmpeg-4.1/doc/examples/encode_video.c

    #!/bin/sh
    
    APP = encode_video
    
    INCLUDE = 
    -I ../bin/include 
    
    LIB = 
    -L ../bin/lib
    
    SRC = encode_video.c
    
    CFLAGS = -g -O0 -lstdc++
    
    LDFLAGS = -lavformat -lavdevice -lavfilter -lavcodec -lavutil -lswscale -lswresample -lm -pthread -ldl -lz -llzma -lx264
    
    out: 
        gcc $(SRC) -o $(APP) $(LIB) $(INCLUDE) $(CFLAGS) $(LDFLAGS)
    
    clean:
        rm encode_video

    ./encode_video test.h264 libx264

    ./encode_video test.mp4 mpeg4

    3. decode

    3.0 avcodec_send_packet + avcodec_receive_frame

    ffmpeg-4.1/doc/examples/decode_video.c (decode h264 video stream from inbuf)

    1) find decoder

    eg: AV_CODEC_ID_H264

        if (argc <= 2) {
            fprintf(stderr, "Usage: %s <input file> <output file>
    ", argv[0]);
            exit(0);
        }
        filename    = argv[1];
        outfilename = argv[2];
    
        pkt = av_packet_alloc();
        if (!pkt)
            exit(1);
    
        /* set end of buffer to 0 (this ensures that no overreading happens for damaged MPEG streams) */
        memset(inbuf + INBUF_SIZE, 0, AV_INPUT_BUFFER_PADDING_SIZE);
    
        /* find the MPEG-1 video decoder */
        //codec = avcodec_find_decoder(AV_CODEC_ID_MPEG1VIDEO);
        codec = avcodec_find_decoder(AV_CODEC_ID_H264);
        if (!codec) {
            fprintf(stderr, "Codec not found
    ");
            exit(1);
        }

    2) decode

    ret = avcodec_send_packet(dec_ctx, pkt);
    while (ret >= 0) {
        ret = avcodec_receive_frame(dec_ctx, frame);
    }

    ./decode_video test.h264 ttt

    3.1 avcodec_decode_video2

    decode h264 video stream from file

    ffmpeg-4.1/tests/api/api-h264-test.c

    ffmpeg-4.1/tests/api/api-band-test.c

    4. avio + decode (Custom AVIOContext + H264 decode)

    4.1 Custom AVIOContext vs File as Input Source

    ffmpeg-4.1/doc/examples/avio_reading.c + ffmpeg-4.1/tests/api/api-h264-test.c(ffmpeg-4.1/tests/api/api-band-test.c)

    /*
     * Copyright (c) 2015 Ludmila Glinskih
     *
     * Permission is hereby granted, free of charge, to any person obtaining a copy
     * of this software and associated documentation files (the "Software"), to deal
     * in the Software without restriction, including without limitation the rights
     * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     * copies of the Software, and to permit persons to whom the Software is
     * furnished to do so, subject to the following conditions:
     *
     * The above copyright notice and this permission notice shall be included in
     * all copies or substantial portions of the Software.
     *
     * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
     * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
     * THE SOFTWARE.
     */
    
    /**
     * H264 codec test.
     */
    
    #define Custom_AVIOContext (1)
    
    #include "libavutil/adler32.h"
    #include "libavcodec/avcodec.h"
    #include "libavformat/avformat.h"
    #include "libavutil/imgutils.h"
    
    #if Custom_AVIOContext
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavformat/avio.h>
    #include <libavutil/file.h>
    
    struct buffer_data {
        uint8_t *ptr;
        size_t size; ///< size left in the buffer
    };
    
    static int read_packet(void *opaque, uint8_t *buf, int buf_size)
    {
        struct buffer_data *bd = (struct buffer_data *)opaque;
        buf_size = FFMIN(buf_size, bd->size);
    
        if (!buf_size)
            return AVERROR_EOF;
    
        //printf("ptr:%p size:%zu
    ", bd->ptr, bd->size);
        //printf("buf_size:%d
    ", buf_size);
    
        /* copy internal buffer data to buf */
        memcpy(buf, bd->ptr, buf_size);
        bd->ptr  += buf_size;
        bd->size -= buf_size;
    
        return buf_size;
    }
    #endif
    
    static int video_decode_example(const char *input_filename)
    {
        AVCodec *codec = NULL;
        AVCodecContext *ctx= NULL;
        AVCodecParameters *origin_par = NULL;
        AVFrame *fr = NULL;
        uint8_t *byte_buffer = NULL;
        AVPacket pkt;
        AVFormatContext *fmt_ctx = NULL;
        int number_of_written_bytes;
        int video_stream;
        int got_frame = 0;
        int byte_buffer_size;
        int i = 0;
        int result;
        int end_of_stream = 0;
    
    #if Custom_AVIOContext
        AVIOContext *avio_ctx = NULL;
        uint8_t *buffer = NULL, *avio_ctx_buffer = NULL;
        size_t buffer_size, avio_ctx_buffer_size = 4096;
        int ret = 0;
        struct buffer_data bd = { 0 };
    
        /* slurp file content into buffer */
        ret = av_file_map(input_filename, &buffer, &buffer_size, 0, NULL);
        if (ret < 0)
            return -1;
    
        /* fill opaque structure used by the AVIOContext read callback */
        bd.ptr  = buffer;
        bd.size = buffer_size;
    
        if (!(fmt_ctx = avformat_alloc_context())) {
            ret = AVERROR(ENOMEM);
            return -1;
        }
    
        avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
        if (!avio_ctx_buffer) {
            ret = AVERROR(ENOMEM);
            return -1;
        }
        avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                      0, &bd, &read_packet, NULL, NULL);
        if (!avio_ctx) {
            ret = AVERROR(ENOMEM);
            return -1;
        }
        fmt_ctx->pb = avio_ctx;
    
        
        result = avformat_open_input(&fmt_ctx, NULL, NULL, NULL);
    #else
        result = avformat_open_input(&fmt_ctx, input_filename, NULL, NULL);
    #endif
    
        if (result < 0) {
            av_log(NULL, AV_LOG_ERROR, "Can't open file
    ");
            return result;
        }
    
        result = avformat_find_stream_info(fmt_ctx, NULL);
        if (result < 0) {
            av_log(NULL, AV_LOG_ERROR, "Can't get stream info
    ");
            return result;
        }
    
        video_stream = av_find_best_stream(fmt_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0);
        if (video_stream < 0) {
          av_log(NULL, AV_LOG_ERROR, "Can't find video stream in input file
    ");
          return -1;
        }
    
        origin_par = fmt_ctx->streams[video_stream]->codecpar;
    
        codec = avcodec_find_decoder(origin_par->codec_id);
        if (!codec) {
            av_log(NULL, AV_LOG_ERROR, "Can't find decoder
    ");
            return -1;
        }
    
        ctx = avcodec_alloc_context3(codec);
        if (!ctx) {
            av_log(NULL, AV_LOG_ERROR, "Can't allocate decoder context
    ");
            return AVERROR(ENOMEM);
        }
    
        result = avcodec_parameters_to_context(ctx, origin_par);
        if (result) {
            av_log(NULL, AV_LOG_ERROR, "Can't copy decoder context
    ");
            return result;
        }
    
        result = avcodec_open2(ctx, codec, NULL);
        if (result < 0) {
            av_log(ctx, AV_LOG_ERROR, "Can't open decoder
    ");
            return result;
        }
    
        fr = av_frame_alloc();
        if (!fr) {
            av_log(NULL, AV_LOG_ERROR, "Can't allocate frame
    ");
            return AVERROR(ENOMEM);
        }
    
        byte_buffer_size = av_image_get_buffer_size(ctx->pix_fmt, ctx->width, ctx->height, 16);
        byte_buffer = av_malloc(byte_buffer_size);
        if (!byte_buffer) {
            av_log(NULL, AV_LOG_ERROR, "Can't allocate buffer
    ");
            return AVERROR(ENOMEM);
        }
    
        printf("#tb %d: %d/%d
    ", video_stream, fmt_ctx->streams[video_stream]->time_base.num, fmt_ctx->streams[video_stream]->time_base.den);
        i = 0;
        av_init_packet(&pkt);
        do {
            if (!end_of_stream)
                if (av_read_frame(fmt_ctx, &pkt) < 0)
                    end_of_stream = 1;
            if (end_of_stream) {
                pkt.data = NULL;
                pkt.size = 0;
            }
            if (pkt.stream_index == video_stream || end_of_stream) {
                got_frame = 0;
                if (pkt.pts == AV_NOPTS_VALUE)
                    pkt.pts = pkt.dts = i;
                result = avcodec_decode_video2(ctx, fr, &got_frame, &pkt);
                if (result < 0) {
                    av_log(NULL, AV_LOG_ERROR, "Error decoding frame
    ");
                    return result;
                }
                if (got_frame) {
                    number_of_written_bytes = av_image_copy_to_buffer(byte_buffer, byte_buffer_size,
                                            (const uint8_t* const *)fr->data, (const int*) fr->linesize,
                                            ctx->pix_fmt, ctx->width, ctx->height, 1);
                    if (number_of_written_bytes < 0) {
                        av_log(NULL, AV_LOG_ERROR, "Can't copy image to buffer
    ");
                        return number_of_written_bytes;
                    }
    
                    //printf("number_of_written_bytes %d %dx%d
    ", number_of_written_bytes, ctx->width, ctx->height);
    
                    printf("%d, %10"PRId64", %10"PRId64", %8"PRId64", %8d, 0x%08lx
    ", video_stream,
                            fr->pts, fr->pkt_dts, fr->pkt_duration,
                            number_of_written_bytes, av_adler32_update(0, (const uint8_t*)byte_buffer, number_of_written_bytes));
                }
                av_packet_unref(&pkt);
                av_init_packet(&pkt);
            }
            i++;
        } while (!end_of_stream || got_frame);
    
        av_packet_unref(&pkt);
        av_frame_free(&fr);
        avcodec_close(ctx);
        avformat_close_input(&fmt_ctx);
        avcodec_free_context(&ctx);
        av_freep(&byte_buffer);
        return 0;
    }
    
    int main(int argc, char **argv)
    {
        if (argc < 2)
        {
            av_log(NULL, AV_LOG_ERROR, "Incorrect input
    ");
            return 1;
        }
    
        if (video_decode_example(argv[1]) != 0)
            return 1;
    
        return 0;
    }

    4.2 Custom AVIOContext vs File as Input Source

    tutorial01.c

    // tutorial01.c
    // Code based on a tutorial by Martin Bohme (boehme@inb.uni-luebeckREMOVETHIS.de)
    // Tested on Gentoo, CVS version 5/01/07 compiled with GCC 4.1.1
    // With updates from https://github.com/chelyaev/ffmpeg-tutorial
    // Updates tested on:
    // LAVC 54.59.100, LAVF 54.29.104, LSWS 2.1.101 
    // on GCC 4.7.2 in Debian February 2015
    
    // A small sample program that shows how to use libavformat and libavcodec to
    // read video from a file.
    //
    // Use
    //
    // gcc -o tutorial01 tutorial01.c -lavformat -lavcodec -lswscale -lz
    //
    // to build (assuming libavformat and libavcodec are correctly installed
    // your system).
    //
    // Run using
    //
    // tutorial01 myvideofile.mpg
    //
    // to write the first five frames from "myvideofile.mpg" to disk in PPM
    // format.
    
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libswscale/swscale.h>
    
    #include <stdio.h>
    
    // compatibility with newer API
    #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
    #define av_frame_alloc avcodec_alloc_frame
    #define av_frame_free avcodec_free_frame
    #endif
    
    void SaveFrame(AVFrame *pFrame, int width, int height, int iFrame) {
      FILE *pFile;
      char szFilename[32];
      int  y;
      
      // Open file
      sprintf(szFilename, "frame%d.ppm", iFrame);
      pFile=fopen(szFilename, "wb");
      if(pFile==NULL)
        return;
      
      // Write header
      fprintf(pFile, "P6
    %d %d
    255
    ", width, height);
      
      // Write pixel data
      for(y=0; y<height; y++)
        fwrite(pFrame->data[0]+y*pFrame->linesize[0], 1, width*3, pFile);
      
      // Close file
      fclose(pFile);
    }
    
    #define Custom_AVIOContext (1)
    
    #if Custom_AVIOContext
    #include <libavcodec/avcodec.h>
    #include <libavformat/avformat.h>
    #include <libavformat/avio.h>
    #include <libavutil/file.h>
    
    struct buffer_data {
        uint8_t *ptr;
        size_t size; ///< size left in the buffer
    };
    
    static int read_packet(void *opaque, uint8_t *buf, int buf_size)
    {
        struct buffer_data *bd = (struct buffer_data *)opaque;
        buf_size = FFMIN(buf_size, bd->size);
    
        if (!buf_size)
            return AVERROR_EOF;
    
        //printf("ptr:%p size:%zu
    ", bd->ptr, bd->size);
        //printf("buf_size:%d
    ", buf_size);
    
        /* copy internal buffer data to buf */
        memcpy(buf, bd->ptr, buf_size);
        bd->ptr  += buf_size;
        bd->size -= buf_size;
    
        return buf_size;
    }
    #endif
    
    int main(int argc, char *argv[]) {
      // Initalizing these to NULL prevents segfaults!
      AVFormatContext   *pFormatCtx = NULL;
      int               i, videoStream;
      AVCodecContext    *pCodecCtxOrig = NULL;
      AVCodecContext    *pCodecCtx = NULL;
      AVCodec           *pCodec = NULL;
      AVFrame           *pFrame = NULL;
      AVFrame           *pFrameRGB = NULL;
      AVPacket          packet;
      int               frameFinished;
      int               numBytes;
      uint8_t           *buffer = NULL;
      struct SwsContext *sws_ctx = NULL;
    
      if(argc < 2) {
        printf("Please provide a movie file
    ");
        return -1;
      }
      // Register all formats and codecs
      av_register_all();
    
    #if Custom_AVIOContext
        AVIOContext *avio_ctx = NULL;
        uint8_t *avio_ctx_buffer = NULL;
        size_t buffer_size, avio_ctx_buffer_size = 4096;
        int ret = 0;
        struct buffer_data bd = { 0 };
    
        /* slurp file content into buffer */
        ret = av_file_map(argv[1], &buffer, &buffer_size, 0, NULL);
        if (ret < 0)
            return -1;
    
        /* fill opaque structure used by the AVIOContext read callback */
        bd.ptr  = buffer;
        bd.size = buffer_size;
    
        if (!(pFormatCtx = avformat_alloc_context())) {
            ret = AVERROR(ENOMEM);
            return -1;
        }
    
        avio_ctx_buffer = av_malloc(avio_ctx_buffer_size);
        if (!avio_ctx_buffer) {
            ret = AVERROR(ENOMEM);
            return -1;
        }
        avio_ctx = avio_alloc_context(avio_ctx_buffer, avio_ctx_buffer_size,
                                      0, &bd, &read_packet, NULL, NULL);
        if (!avio_ctx) {
            ret = AVERROR(ENOMEM);
            return -1;
        }
        pFormatCtx->pb = avio_ctx;
    
        
      // Open video file
      if(avformat_open_input(&pFormatCtx, NULL, NULL, NULL)!=0)
        return -1; // Couldn't open file
    #else
      // Open video file
      if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL)!=0)
        return -1; // Couldn't open file
    #endif
      
    
      
      // Retrieve stream information
      if(avformat_find_stream_info(pFormatCtx, NULL)<0)
        return -1; // Couldn't find stream information
      
      // Dump information about file onto standard error
      av_dump_format(pFormatCtx, 0, argv[1], 0);
      
      // Find the first video stream
      videoStream=-1;
      for(i=0; i<pFormatCtx->nb_streams; i++)
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO) {
          videoStream=i;
          break;
        }
      if(videoStream==-1)
        return -1; // Didn't find a video stream
      
      // Get a pointer to the codec context for the video stream
      pCodecCtxOrig=pFormatCtx->streams[videoStream]->codec;
      // Find the decoder for the video stream
      pCodec=avcodec_find_decoder(pCodecCtxOrig->codec_id);
      if(pCodec==NULL) {
        fprintf(stderr, "Unsupported codec!
    ");
        return -1; // Codec not found
      }
      // Copy context
      pCodecCtx = avcodec_alloc_context3(pCodec);
      if(avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0) {
        fprintf(stderr, "Couldn't copy codec context");
        return -1; // Error copying codec context
      }
    
      // Open codec
      if(avcodec_open2(pCodecCtx, pCodec, NULL)<0)
        return -1; // Could not open codec
      
      // Allocate video frame
      pFrame=av_frame_alloc();
      
      // Allocate an AVFrame structure
      pFrameRGB=av_frame_alloc();
      if(pFrameRGB==NULL)
        return -1;
    
      // Determine required buffer size and allocate buffer
      numBytes=avpicture_get_size(AV_PIX_FMT_RGB24, pCodecCtx->width,
                      pCodecCtx->height);
      buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
      
      // Assign appropriate parts of buffer to image planes in pFrameRGB
      // Note that pFrameRGB is an AVFrame, but AVFrame is a superset
      // of AVPicture
      avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24,
             pCodecCtx->width, pCodecCtx->height);
      
      // initialize SWS context for software scaling
      sws_ctx = sws_getContext(pCodecCtx->width,
                   pCodecCtx->height,
                   pCodecCtx->pix_fmt,
                   pCodecCtx->width,
                   pCodecCtx->height,
                   AV_PIX_FMT_RGB24,
                   SWS_BILINEAR,
                   NULL,
                   NULL,
                   NULL
                   );
    
      // Read frames and save first five frames to disk
      i=0;
      while(av_read_frame(pFormatCtx, &packet)>=0) {
        // Is this a packet from the video stream?
        if(packet.stream_index==videoStream) {
          // Decode video frame
          avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
          
          // Did we get a video frame?
          if(frameFinished) {
        // Convert the image from its native format to RGB
        sws_scale(sws_ctx, (uint8_t const * const *)pFrame->data,
              pFrame->linesize, 0, pCodecCtx->height,
              pFrameRGB->data, pFrameRGB->linesize);
        
        // Save the frame to disk
        if(++i<=5)
          SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, 
                i);
          }
        }
        
        // Free the packet that was allocated by av_read_frame
        av_free_packet(&packet);
      }
      
      // Free the RGB image
      av_free(buffer);
      av_frame_free(&pFrameRGB);
      
      // Free the YUV frame
      av_frame_free(&pFrame);
      
      // Close the codecs
      avcodec_close(pCodecCtx);
      avcodec_close(pCodecCtxOrig);
    
      // Close the video file
      avformat_close_input(&pFormatCtx);
      
      return 0;
    }

    5. mux

    5.1 ffmpeg-4.1/doc/examples/muxing.c

    This program generates a synthetic aac audio and h264 video frames, encodes and muxes them into a mp4/ps/ts/flv ... and so on container.

        fmt = oc->oformat;
    
        fmt->video_codec = AV_CODEC_ID_H264; 
        fmt->audio_codec = AV_CODEC_ID_MP2;   //ffmpeg-4.2.2 default support
        //fmt->audio_codec = AV_CODEC_ID_AAC; //ffmpeg-4.1 default support
    
        /* Add the audio and video streams using the default format codecs
         * and initialize the codecs. */
        if (fmt->video_codec != AV_CODEC_ID_NONE) {
            add_stream(&video_st, oc, &video_codec, fmt->video_codec);
            have_video = 1;
            encode_video = 1;
        }
        if (fmt->audio_codec != AV_CODEC_ID_NONE) {
            add_stream(&audio_st, oc, &audio_codec, fmt->audio_codec);
            have_audio = 1;
            encode_audio = 1;
        }

    dong@ubuntu:~/2019-nCoV/container$ tree
    .
    ├── build.sh
    ├── muxing
    ├── muxing.c
    ├── test.avi
    ├── test.flv
    ├── test.mp4
    ├── test.ps
    └── test.ts

    0 directories, 8 files

    log_packet printf output audio/audio package info.

    static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt);

    5.2 mp4 muxer

    https://github.com/slmax2017/ffmpeg_mp4_h264_mux

    #include <iostream>
    #include <vector>
    #include <algorithm>
    using namespace std;
    
    
    extern "C" {
    #include "libavcodec/avcodec.h"
    #include "libavutil/mem.h"    
    #include "libavutil/imgutils.h"
    #include "libavformat/avformat.h"
    }
    
    int err = -1;
    char buf[1024] = { 0 };
    #define IN_VEDIO_FILE  "cuc_ieschool.h264"
    #define IN_AUDIO_FILE  "cuc_ieschool.mp3"
    #define OUT_FILE "cuc_ieschool.mp4"
    
    #define  ptr_check(x) 
                do {
                    if (!x){
                        printf("operator fail"); 
                        return -1; 
                    }
                }while(0) 
    
    #define void_handle(x) 
                if ((err = (x)) < 0) {
                    memset(buf, 0, 1024); 
                    av_strerror(err, buf, 1024); 
                    printf("err msg = %s", buf); 
                    return -1; 
                }
    
    #define ret_handle(x, r) 
                if ((r = (x)) < 0) {
                    memset(buf, 0, 1024); 
                    av_strerror(r, buf, 1024); 
                    printf("err msg = %s", buf); 
                    return -1; 
                }   
    
    int main()
    {
        AVFormatContext *in_vedio_ctx = NULL, *in_audio_ctx = NULL, *out_ctx = NULL;
        vector<int> stream_indexs;
        bool isVedio = true;
    
        //h264 info
        void_handle(avformat_open_input(&in_vedio_ctx, IN_VEDIO_FILE, NULL, NULL));
        void_handle(avformat_find_stream_info(in_vedio_ctx, NULL));
    
        //mp3 info
        void_handle(avformat_open_input(&in_audio_ctx, IN_AUDIO_FILE, NULL, NULL));
        void_handle(avformat_find_stream_info(in_audio_ctx, NULL));
    
        //mp4 init
        void_handle(avformat_alloc_output_context2(&out_ctx, NULL, NULL, OUT_FILE));
    
        //get stream
        int vedio_stream_index = -1, audio_stream_index = -1;
        ret_handle(av_find_best_stream(in_vedio_ctx, AVMEDIA_TYPE_VIDEO, -1, -1, NULL, 0), vedio_stream_index);
        ret_handle(av_find_best_stream(in_audio_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0), audio_stream_index);
    
        stream_indexs.push_back(vedio_stream_index);
        stream_indexs.push_back(audio_stream_index);
    
        //为输出上下文创建流
        for_each(stream_indexs.begin(), stream_indexs.end(), [&](int index) {
            AVStream *out_stream = avformat_new_stream(out_ctx, NULL);
            ptr_check(out_stream);
            void_handle(avcodec_parameters_from_context(out_stream->codecpar,
                isVedio ? in_vedio_ctx->streams[index]->codec : in_audio_ctx->streams[index]->codec));
    
            isVedio = false;
            if (out_ctx->oformat->flags & AVFMT_GLOBALHEADER) {
                out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
            }
    
        });
    
        //打开输出文件
        if (!(out_ctx->oformat->flags & AVFMT_NOFILE)) {
            void_handle(avio_open(&out_ctx->pb, OUT_FILE, AVIO_FLAG_READ_WRITE));
        }
    
        //写入文件头
        avformat_write_header(out_ctx, NULL);
    
        //开始写文件
        AVPacket *packet = av_packet_alloc();
        int64_t ts_a = 0, ts_b = 0;
        int64_t *ts_p = NULL;
        int out_stream_index = -1;
        AVFormatContext *cur_ctx = NULL;
        AVStream *cur_stream = NULL;
        int frame = 0;
    
        while (1) {
    
            //指定当前读取视频还是音视
            if (av_compare_ts(ts_a, in_vedio_ctx->streams[vedio_stream_index]->time_base, ts_b, in_audio_ctx->streams[audio_stream_index]->time_base) <= 0) {
                cur_ctx = in_vedio_ctx;
                ts_p = &ts_a;
                cur_stream = in_vedio_ctx->streams[vedio_stream_index];
                out_stream_index = 0;
            } else {
                cur_ctx = in_audio_ctx;
                ts_p = &ts_b;
                cur_stream = in_audio_ctx->streams[audio_stream_index];
                out_stream_index = 1;
            }
    
            if (av_read_frame(cur_ctx, packet) < 0) {
                memset(buf, 0, 1024);
                av_strerror(err, buf, 1024);
                printf(buf);
                break;
            }
    
            //计算pts dts, 这里只是计算出当前的刻度,后面需要再计算成具体的时间
            if (packet->pts == AV_NOPTS_VALUE) {
    
                //计算出输入(原始)视频一帧多长时间,结果单位为微妙
                int64_t each_frame_time = (double)AV_TIME_BASE / av_q2d(cur_stream->r_frame_rate);   
    
                //以原始一帧的持续时间除以时间基,则时间刻度就有了,由于时间基的单位为秒.而持续时间(each_frame_time)为微妙,故还需要除以AV_TIME_BASE
                packet->pts = (double)(frame++ * each_frame_time) / (double)(av_q2d(cur_stream->time_base) * AV_TIME_BASE);  
                packet->dts = packet->pts;
    
                //一帧的时间为each_frame_time微妙,除以AV_TIME_BASE就是秒,再除以时间基,则时间刻度就出来了.
                packet->duration = (double)each_frame_time / (double)(av_q2d(cur_stream->time_base) * AV_TIME_BASE);
            }
    
            *ts_p = packet->pts;
    
            //计算pts对应的具体的时间
            av_packet_rescale_ts(packet, cur_stream->time_base, out_ctx->streams[out_stream_index]->time_base);
            packet->stream_index = out_stream_index;
            printf("write file pts = %lld, index = %d
    ", packet->pts, packet->stream_index);
    
            //写入文件
            void_handle(av_interleaved_write_frame(out_ctx, packet));
    
            av_packet_unref(packet);
        }
    
    
        //写文件尾
        void_handle(av_write_trailer(out_ctx));
    
        if (!(out_ctx->oformat->flags & AVFMT_NOFILE)) {
            void_handle(avio_close(out_ctx->pb));
        }
        avformat_close_input(&in_audio_ctx);
        avformat_close_input(&in_vedio_ctx);
        avformat_free_context(out_ctx);
        av_packet_free(&packet);
        return 0;
    }

    g++ main.cpp -o main `pkg-config --cflags --libs libavdevice libavformat libavfilter libavcodec libswresample libswscale libavutil` -lx264 -std=c++11

    最简单的基于FFmpeg的封装格式处理系列文章列表:

    最简单的基于FFmpeg的封装格式处理:视音频分离器简化版(demuxer-simple)

    最简单的基于FFmpeg的封装格式处理:视音频分离器(demuxer)

    最简单的基于FFmpeg的封装格式处理:视音频复用器(muxer)

    最简单的基于FFMPEG的封装格式处理:封装格式转换(remuxer)

    6. Tutorial 05: Synching Video 

    7. Tutorial 06: Synching Audio

    http://dranger.com/ffmpeg/tutorial05.html

    http://dranger.com/ffmpeg/tutorial06.html

    8. Tutorial 07: Seeking

    http://dranger.com/ffmpeg/tutorial07.html

    debug

    9. avio + mux

    Avidemux is a simple platform video editor for Linux, Windows and MacOsX.

    https://github.com/mean00/avidemux2

    http://www.ffmpeg-archive.org/How-to-mux-a-raw-h264-es-into-some-container-without-x264-installed-td4663139.html

  • 相关阅读:
    mac idea 更换主题
    记一次Sonarqube踩坑实录
    Mysql 常用数据类型
    Spring Cloud 整合分布式链路追踪系统Sleuth和ZipKin实战,分析系统瓶颈
    git clone克隆github仓库慢,问题解决
    SpringBoot 解决跨域问题
    Android 中的敏感信息泄露
    Drozer 测试 APP
    Drozer 安装踩坑日记
    安卓测试笔记--工具安装
  • 原文地址:https://www.cnblogs.com/dong1/p/10268009.html
Copyright © 2011-2022 走看看