I. Building FFmpeg in Ubuntu
dong@ubuntu:~/2019-nCoV$ tree
.
├── build.sh
├── fdk-aac-2.0.0.tar.gz
├── ffmpeg-4.1.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
└── zlib-1.2.11.tar.gz
0 directories, 18 files
dong@ubuntu:~/2019-nCoV$
build.sh
export PKG_CONFIG_PATH=/home/dong/2019-nCoV/_install/lib/pkgconfig:$PKG_CONFIG_PATH
#3 tar xvf zlib-1.2.11.tar.gz cd zlib-1.2.11
CFLAGS="-O3 -fPIC" ./configure --prefix=/home/dong/2019-nCoV/_install --enable-shared 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 --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 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 --disable-asm --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 ..
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
source ~/.bashrc
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
dong@ubuntu:~/2019-nCoV$./build
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. decode
2.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); }
2.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
3. avio + decode (Custom AVIOContext + H264 decode)
3.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; }
3.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; }
4. mux
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. Tutorial 05: Synching Video
6. Tutorial 06: Synching Audio
http://dranger.com/ffmpeg/tutorial05.html
http://dranger.com/ffmpeg/tutorial06.html
7. Tutorial 07: Seeking
http://dranger.com/ffmpeg/tutorial07.html
debug
8. avio + mux
https://github.com/gjwang/ffmpeg_mp4_mux
https://github.com/FFmpeg/FFmpeg/releases/tag/n2.4.4
err: Using AVStream.codec to pass codec parameters to muxers is deprecated, use AVStream.codecpar instead.
https://github.com/mean00/avidemux2/commit/d2b1f44087b5774f00410db77fb9c560095939cc
http://www.ffmpeg-archive.org/How-to-mux-a-raw-h264-es-into-some-container-without-x264-installed-td4663139.html
http://libav-users.943685.n4.nabble.com/Libav-user-muxing-h264-aac-stream-td4658388.html
https://github.com/slmax2017/ffmpeg_mp4_h264_mux/blob/master/main.cpp
https://github.com/ssuqin-kk/FFmpegDemo/tree/master/FFmpegDemo/mp4convert