FFmpeg Programming Interface (API) Guide for Beginners

I. Building FFmpeg in Ubuntu

Add environment variable

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

 

FFmpeg build

build.sh

./configure --prefix=/home/dong/2019-nCoV/_install --disable-x86asm
make
make install

 

ffmpeg + x264

# ffmpeg + x264
# ffmpeg
./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared --enable-static --enable-pic
make && sudo make install
# x264
./configure --prefix=/home/dong/2019-nCoV/_install --enable-libx264 --enable-gpl --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 && sudo make install
# build
gcc muxing.c -o muxing `pkg-config --cflags --libs libavdevice libavformat libavfilter libavcodec libswresample libswscale libavutil` -lx264

 

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 不需要sdl-1.xx版本了
#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 ..
#bug1 https://blog.csdn.net/bdemq/article/details/104051151
#bug2 https://blog.csdn.net/tenorange/article/details/86627337

 

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\n", 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\n"
                "API example program to show how to read from a custom buffer "
                "accessed through AVIOContext.\n", 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\n");
        goto end;
    }

    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not find stream information\n");
        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\n", 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\n", 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\n"
                "API example program to show how to read from a custom buffer "
                "accessed through AVIOContext.\n", 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\n");
        goto end;
    }

    ret = avformat_find_stream_info(fmt_ctx, NULL);
    if (ret < 0) {
        fprintf(stderr, "Could not find stream information\n");
        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\n", 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>\n", 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\n");
        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\n", bd->ptr, bd->size);
    //printf("buf_size:%d\n", 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\n");
        return result;
    }

    result = avformat_find_stream_info(fmt_ctx, NULL);
    if (result < 0) {
        av_log(NULL, AV_LOG_ERROR, "Can't get stream info\n");
        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\n");
      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\n");
        return -1;
    }

    ctx = avcodec_alloc_context3(codec);
    if (!ctx) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate decoder context\n");
        return AVERROR(ENOMEM);
    }

    result = avcodec_parameters_to_context(ctx, origin_par);
    if (result) {
        av_log(NULL, AV_LOG_ERROR, "Can't copy decoder context\n");
        return result;
    }

    result = avcodec_open2(ctx, codec, NULL);
    if (result < 0) {
        av_log(ctx, AV_LOG_ERROR, "Can't open decoder\n");
        return result;
    }

    fr = av_frame_alloc();
    if (!fr) {
        av_log(NULL, AV_LOG_ERROR, "Can't allocate frame\n");
        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\n");
        return AVERROR(ENOMEM);
    }

    printf("#tb %d: %d/%d\n", 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\n");
                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\n");
                    return number_of_written_bytes;
                }

                //printf("number_of_written_bytes %d %dx%d\n", number_of_written_bytes, ctx->width, ctx->height);

                printf("%d, %10"PRId64", %10"PRId64", %8"PRId64", %8d, 0x%08lx\n", 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\n");
        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\n%d %d\n255\n", 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\n", bd->ptr, bd->size);
    //printf("buf_size:%d\n", 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\n");
    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!\n");
    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\n", 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

 

网友整理得很好

https://www.cnblogs.com/leisure_chn/category/1351812.html

 

posted @ 2019-01-14 17:24  dong1  阅读(2182)  评论(0编辑  收藏  举报