1、FFmpeg 源码目录结构
目录 说明 libavcodec 提供了一系列编码器的实现 libavformat 实现在刘协议、容器格式及其本 IO 访问 libavutil 包括了 hash 器、解码器和各种工具函数 libavfilter 提供了各种音视频过滤器 libavdevice 提供了访问捕获设备和回放设备的接口 libswresample 实现了混音和重采样 libswscale 实现了色彩转换和缩放功能
2、FFmpeg 日志系统
include < libavutil/ log. h>
av_log_set_level ( AV_LOG_DEBUG)
av_log ( NULL , AV_LOG_INFO, "...%s\n" , op)
AV_LOG_ERROR、AV_LOG_WARNING、AV_LOG_INFO、AV_LOG_DEBUG
#include <stdio.h>
#include <libavutil/log.h>
int main ( int argc, char * argv[ ] ) {
av_log_set_level ( AV_LOG_DEBUG) ;
av_log ( NULL , AV_LOG_DEBUG, "Hello FFmpeg!=>%s\n" , "debug信息" ) ;
av_log ( NULL , AV_LOG_INFO, "Hello FFmpeg!=>%s\n" , "info信息" ) ;
av_log ( NULL , AV_LOG_WARNING, "Hello FFmpeg!=>%s\n" , "warning信息" ) ;
av_log ( NULL , AV_LOG_ERROR, "Hello FFmpeg!=>%s\n" , "error信息" ) ;
return 0 ;
}
clang - g - o 1 _ff_log 1 _ff_log. c - I/ usr/ local/ ffmpeg/ include - L/ usr/ local/ ffmpeg/ lib - lavutil
或者
clang - g - o 1 _ff_log 1 _ff_log. c `pkg- config -- cflags -- libs libavutil`
- g: 输出有调试信息的运行文件
- o: 输出执行文 件
- L: 指定库的路径
- I: 指定头文件的路径
. / 1 _ff_log
3、FFmpeg 文件的删除与重命名
avpriv_io_delete ( )
avpriv_io_move ( )
#include <stdio.h>
#include <libavformat/avformat.h>
int main ( int argc, char * argv[ ] ) {
int ret;
ret = avpriv_io_move ( "./files/11.txt" , "./files/22.txt" ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR, "failed to rename\n" ) ;
return - 1 ;
}
av_log ( NULL , AV_LOG_INFO, "success to rename\n" ) ;
ret = avpriv_io_delete ( "./files/mytestfile.txt" ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR, "delete failed\n" ) ;
return - 1 ;
}
av_log ( NULL , AV_LOG_INFO, "success to delete\n" ) ;
return 0 ;
}
clang - g - o 2 _ff_file 2 _ff_file. c `pkg- config -- cflags -- libs libavformat`
. / 2 _ff_file
4、FFmpeg 操作目录重要函数
avio_open_dir ( )
avio_read_dir ( )
avio_close_dir ( )
AVIODirContext
AVIODirEntry
#include <stdio.h>
#include <libavutil/avutil.h>
#include <libavformat/avformat.h>
int main ( int argc, char * argv[ ] ) {
AVIODirContext * ctx = NULL ;
AVIODirEntry * entry = NULL ;
av_log_set_level ( AV_LOG_DEBUG) ;
int ret = avio_open_dir ( & ctx, "./files" , NULL ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR, "Cant open dir:%s\n" , av_err2str ( ret) ) ;
goto __fail;
}
while ( 1 ) {
ret = avio_read_dir ( ctx, & entry) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR, "Cant red dir:&s\n" , av_err2str ( ret) ) ;
goto __fail;
}
if ( ! entry) break ;
av_log ( NULL , AV_LOG_INFO, "文件名:%s ,文件大小:%" PRId64"\n" , entry-> name, entry-> size) ;
avio_free_directory_entry ( & entry) ;
}
__fail:
avio_close_dir ( & ctx) ;
return 0 ;
}
clang - g - o 3 _ff_dir 3 _ff_dir. c `pkg- config -- cflags -- libs libavutil libavformat`
. / 3 _ff_dir
5、FFmpeg 多媒体文件基本概念
多媒体文件其实是一个容器 在容器里面有很多流(Stream/Track),每个流互不相交 每个流是由不同的编码器编码的 从流中读出的数据称为包 在一个包中包含着一个或者多个帧 几个重要的结构体
AVFotmatContext
AVStream
AVPacket
FFmpeg 操作流数据的基本步骤:
6、FFmpeg 打印音/视频信息
av_register_arr ( )
avfotmat_open_input ( )
avformat_close_input ( )
av_dump_format ( )
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avformat.h>
int main ( int argc, char * argv[ ] ) {
int ret;
AVFormatContext * fmt_ctx = NULL ;
av_log_set_level ( AV_LOG_INFO) ;
av_register_all ( ) ;
ret = avformat_open_input ( & fmt_ctx, "./files/sample.mp4" , NULL , NULL ) ;
if ( ret < 0 ) {
av_log ( NULL , AV_LOG_ERROR, "Can't open file: %s\n" , av_err2str ( ret) ) ;
return - 1 ;
}
av_dump_format ( fmt_ctx, 0 , "./files/sample.mp4" , 0 ) ;
avformat_close_input ( & fmt_ctx) ;
return 0 ;
}
clang - g - o 4 _ff_meta 4 _ff_meta. c `pkg- config -- cflags -- libs libavutil libavformat`
. / 4 _ff_meta
7、FFmpeg 抽取音频数据
av_init_packet ( )
av_find_best_stream ( )
av_read_frame ( )
av_packet_unref ( )
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
#define ADTS_HEADER_LEN 7;
static int get_audio_obj_type ( int aactype) {
switch ( aactype) {
case 0 :
case 2 :
case 3 :
return aactype + 1 ;
case 1 :
case 4 :
case 28 :
return 2 ;
default :
return 2 ;
}
}
static int get_sample_rate_index ( int freq, int aactype) {
int i = 0 ;
int freq_arr[ 13 ] = {
96000 , 88200 , 64000 , 48000 , 44100 , 32000 ,
24000 , 22050 , 16000 , 12000 , 11025 , 8000 , 7350
} ;
if ( aactype == 28 || aactype == 4 ) {
freq / = 2 ;
}
for ( i = 0 ; i < 13 ; i++ ) {
if ( freq == freq_arr[ i] ) {
return i;
}
}
return 4 ;
}
static int get_channel_config ( int channels, int aactype) {
if ( aactype == 28 ) {
return ( channels / 2 ) ;
}
return channels;
}
static void adts_header ( char * szAdtsHeader, int dataLen, int aactype, int frequency, int channels) {
int audio_object_type = get_audio_obj_type ( aactype) ;
int sampling_frequency_index = get_sample_rate_index ( frequency, aactype) ;
int channel_config = get_channel_config ( channels, aactype) ;
printf ( "aot=%d, freq_index=%d, channel=%d\n" , audio_object_type, sampling_frequency_index, channel_config) ;
int adtsLen = dataLen + 7 ;
szAdtsHeader[ 0 ] = 0xff ;
szAdtsHeader[ 1 ] = 0xf0 ;
szAdtsHeader[ 1 ] | = ( 0 << 3 ) ;
szAdtsHeader[ 1 ] | = ( 0 << 1 ) ;
szAdtsHeader[ 1 ] | = 1 ;
szAdtsHeader[ 2 ] =
( audio_object_type - 1 ) << 6 ;
szAdtsHeader[ 2 ] | =
( sampling_frequency_index & 0x0f ) << 2 ;
szAdtsHeader[ 2 ] | = ( 0 << 1 ) ;
szAdtsHeader[ 2 ] | =
( channel_config & 0x04 ) >> 2 ;
szAdtsHeader[ 3 ] = ( channel_config & 0x03 ) << 6 ;
szAdtsHeader[ 3 ] | = ( 0 << 5 ) ;
szAdtsHeader[ 3 ] | = ( 0 << 4 ) ;
szAdtsHeader[ 3 ] | = ( 0 << 3 ) ;
szAdtsHeader[ 3 ] | = ( 0 << 2 ) ;
szAdtsHeader[ 3 ] | = ( ( adtsLen & 0x1800 ) >> 11 ) ;
szAdtsHeader[ 4 ] = ( uint8_t) ( ( adtsLen & 0x7f8 ) >> 3 ) ;
szAdtsHeader[ 5 ] = ( uint8_t) ( ( adtsLen & 0x7 ) << 5 ) ;
szAdtsHeader[ 5 ] | = 0x1f ;
szAdtsHeader[ 6 ] = 0xfc ;
}
int main ( int argc, char * argv[ ] ) {
int err_code;
char errors[ 1024 ] ;
const char * src_filename = "./files/sample.mp4" ;
const char * dst_filename = "./files/sample.aac" ;
FILE * dst_fd = NULL ;
int audio_stream_index = - 1 ;
int len;
AVFormatContext * ofmt_ctx = NULL ;
AVOutputFormat * output_fmt = NULL ;
AVStream * out_stream = NULL ;
AVFormatContext * fmt_ctx = NULL ;
AVFrame * frame = NULL ;
AVPacket pkt;
av_log_set_level ( AV_LOG_DEBUG) ;
if ( src_filename == NULL || dst_filename == NULL ) {
av_log ( NULL , AV_LOG_DEBUG, "src or dts file is null, plz check them!\n" ) ;
return - 1 ;
}
dst_fd = fopen ( dst_filename, "wb" ) ;
if ( ! dst_fd) {
av_log ( NULL , AV_LOG_DEBUG, "Could not open destination file %s\n" , dst_filename) ;
return - 1 ;
}
if ( ( err_code = avformat_open_input ( & fmt_ctx, src_filename, NULL , NULL ) ) < 0 ) {
av_strerror ( err_code, errors, 1024 ) ;
av_log ( NULL , AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n" ,
src_filename,
err_code,
errors) ;
return - 1 ;
}
if ( ( err_code = avformat_find_stream_info ( fmt_ctx, NULL ) ) < 0 ) {
av_strerror ( err_code, errors, 1024 ) ;
av_log ( NULL , AV_LOG_DEBUG, "failed to find stream information: %s, %d(%s)\n" ,
src_filename,
err_code,
errors) ;
return - 1 ;
}
av_dump_format ( fmt_ctx, 0 , src_filename, 0 ) ;
frame = av_frame_alloc ( ) ;
if ( ! frame) {
av_log ( NULL , AV_LOG_DEBUG, "Could not allocate frame\n" ) ;
return AVERROR ( ENOMEM) ;
}
av_init_packet ( & pkt) ;
pkt. data = NULL ;
pkt. size = 0 ;
audio_stream_index = av_find_best_stream ( fmt_ctx, AVMEDIA_TYPE_AUDIO, - 1 , - 1 , NULL , 0 ) ;
if ( audio_stream_index < 0 ) {
av_log ( NULL , AV_LOG_DEBUG, "Could not find %s stream in input file %s\n" ,
av_get_media_type_string ( AVMEDIA_TYPE_AUDIO) ,
src_filename) ;
return AVERROR ( EINVAL) ;
}
int aac_type = fmt_ctx-> streams[ 1 ] -> codecpar-> profile;
int channels = fmt_ctx-> streams[ 1 ] -> codecpar-> channels;
int sample_rate = fmt_ctx-> streams[ 1 ] -> codecpar-> sample_rate;
if ( fmt_ctx-> streams[ 1 ] -> codecpar-> codec_id != AV_CODEC_ID_AAC) {
av_log ( NULL , AV_LOG_ERROR, "the audio type is not AAC!\n" ) ;
goto __ERROR;
} else {
av_log ( NULL , AV_LOG_INFO, "the audio type is AAC!\n" ) ;
}
while ( av_read_frame ( fmt_ctx, & pkt) >= 0 ) {
if ( pkt. stream_index == audio_stream_index) {
char adts_header_buf[ 7 ] ;
adts_header ( adts_header_buf, pkt. size, aac_type, sample_rate, channels) ;
fwrite ( adts_header_buf, 1 , 7 , dst_fd) ;
len = fwrite ( pkt. data, 1 , pkt. size, dst_fd) ;
if ( len != pkt. size) {
av_log ( NULL , AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n" , len,
pkt. size) ;
}
}
av_packet_unref ( & pkt) ;
}
__ERROR:
avformat_close_input ( & fmt_ctx) ;
if ( dst_fd) {
fclose ( dst_fd) ;
}
return 0 ;
}
clang - g - o 5 _extra_audio 5 _ff_extra_audio. c `pkg- config -- cflags -- libs libavutil libavformat`
. / 5 _extra_audio
8、FFmpeg 抽取视频 H264 数据
Start code
SPS/ PPS
codec-> extradata
#include <stdio.h>
#include <libavutil/log.h>
#include <libavformat/avio.h>
#include <libavformat/avformat.h>
#ifndef AV_WB32
# define AV_WB32(p, val) do { \
uint32_t d = (val); \
((uint8_t*)(p))[3] = (d); \
((uint8_t*)(p))[2] = (d)>>8; \
((uint8_t*)(p))[1] = (d)>>16; \
((uint8_t*)(p))[0] = (d)>>24; \
} while(0)
#endif
#ifndef AV_RB16
# define AV_RB16(x) \
((((const uint8_t*)(x))[0] << 8) | \
((const uint8_t*)(x))[1])
#endif
static int alloc_and_copy ( AVPacket * out,
const uint8_t * sps_pps, uint32_t sps_pps_size,
const uint8_t * in, uint32_t in_size) {
uint32_t offset = out-> size;
uint8_t nal_header_size = 4 ;
int err;
err = av_grow_packet ( out, sps_pps_size + in_size + nal_header_size) ;
if ( err < 0 )
return err;
if ( sps_pps)
memcpy ( out-> data + offset, sps_pps, sps_pps_size) ;
memcpy ( out-> data + sps_pps_size + nal_header_size + offset, in, in_size) ;
if ( ! offset) {
AV_WB32 ( out-> data + sps_pps_size, 1 ) ;
} else {
( out-> data + offset + sps_pps_size) [ 0 ] =
( out-> data + offset + sps_pps_size) [ 1 ] = 0 ;
( out-> data + offset + sps_pps_size) [ 2 ] = 1 ;
}
return 0 ;
}
int h264_extradata_to_annexb ( const uint8_t * codec_extradata, const int codec_extradata_size, AVPacket * out_extradata,
int padding) {
uint16_t unit_size = 0 ;
uint64_t total_size = 0 ;
uint8_t * out = NULL ;
uint8_t unit_nb = 0 ;
uint8_t sps_done = 0 ;
uint8_t sps_seen = 0 ;
uint8_t pps_seen = 0 ;
uint8_t sps_offset = 0 ;
uint8_t pps_offset = 0 ;
const uint8_t * extradata = codec_extradata + 4 ;
static const uint8_t nalu_header[ 4 ] = { 0 , 0 , 0 , 1 } ;
extradata++ ;
sps_offset = pps_offset = - 1 ;
unit_nb = * extradata++ & 0x1f ;
if ( ! unit_nb) {
goto pps;
} else {
sps_offset = 0 ;
sps_seen = 1 ;
}
while ( unit_nb-- ) {
int err;
unit_size = AV_RB16 ( extradata) ;
total_size + = unit_size + 4 ;
if ( total_size > INT_MAX - padding) {
av_log ( NULL , AV_LOG_ERROR,
"Too big extradata size, corrupted stream or invalid MP4/AVCC bitstream\n" ) ;
av_free ( out) ;
return AVERROR ( EINVAL) ;
}
if ( extradata + 2 + unit_size > codec_extradata + codec_extradata_size) {
av_log ( NULL , AV_LOG_ERROR, "Packet header is not contained in global extradata, "
"corrupted stream or invalid MP4/AVCC bitstream\n" ) ;
av_free ( out) ;
return AVERROR ( EINVAL) ;
}
if ( ( err = av_reallocp ( & out, total_size + padding) ) < 0 )
return err;
memcpy ( out + total_size - unit_size - 4 , nalu_header, 4 ) ;
memcpy ( out + total_size - unit_size, extradata + 2 , unit_size) ;
extradata + = 2 + unit_size;
pps:
if ( ! unit_nb && ! sps_done++ ) {
unit_nb = * extradata++ ;
if ( unit_nb) {
pps_offset = total_size;
pps_seen = 1 ;
}
}
}
if ( out) {
memset ( out + total_size, 0 , padding) ;
}
if ( ! sps_seen)
av_log ( NULL , AV_LOG_WARNING,
"Warning: SPS NALU missing or invalid. "
"The resulting stream may not play.\n" ) ;
if ( ! pps_seen)
av_log ( NULL , AV_LOG_WARNING,
"Warning: PPS NALU missing or invalid. "
"The resulting stream may not play.\n" ) ;
out_extradata-> data = out;
out_extradata-> size = total_size;
return 0 ;
}
int h264_mp4toannexb ( AVFormatContext * fmt_ctx, AVPacket * in, FILE * dst_fd) {
AVPacket * out = NULL ;
AVPacket spspps_pkt;
int len;
uint8_t unit_type;
int32_t nal_size;
uint32_t cumul_size = 0 ;
const uint8_t * buf;
const uint8_t * buf_end;
int buf_size;
int ret = 0 , i;
out = av_packet_alloc ( ) ;
buf = in-> data;
buf_size = in-> size;
buf_end = in-> data + in-> size;
do {
ret = AVERROR ( EINVAL) ;
if ( buf + 4 > buf_end)
goto fail;
for ( nal_size = 0 , i = 0 ; i < 4 ; i++ )
nal_size = ( nal_size << 8 ) | buf[ i] ;
buf + = 4 ;
unit_type = * buf & 0x1f ;
if ( nal_size > buf_end - buf || nal_size < 0 )
goto fail;
if ( unit_type == 5 ) {
h264_extradata_to_annexb ( fmt_ctx-> streams[ in-> stream_index] -> codecpar-> extradata,
fmt_ctx-> streams[ in-> stream_index] -> codecpar-> extradata_size,
& spspps_pkt,
AV_INPUT_BUFFER_PADDING_SIZE) ;
if ( ( ret = alloc_and_copy ( out,
spspps_pkt. data, spspps_pkt. size,
buf, nal_size) ) < 0 )
goto fail;
} else {
if ( ( ret = alloc_and_copy ( out, NULL , 0 , buf, nal_size) ) < 0 )
goto fail;
}
len = fwrite ( out-> data, 1 , out-> size, dst_fd) ;
if ( len != out-> size) {
av_log ( NULL , AV_LOG_DEBUG, "warning, length of writed data isn't equal pkt.size(%d, %d)\n" ,
len,
out-> size) ;
}
fflush ( dst_fd) ;
next_nal:
buf + = nal_size;
cumul_size + = nal_size + 4 ;
} while ( cumul_size < buf_size) ;
fail:
av_packet_free ( & out) ;
return ret;
}
int main ( int argc, char * argv[ ] ) {
int err_code;
char errors[ 1024 ] ;
const char * src_filename = "./files/sample.mp4" ;
const char * dst_filename = "./files/sample.h264" ;
FILE * dst_fd = NULL ;
int video_stream_index = - 1 ;
AVFormatContext * fmt_ctx = NULL ;
AVPacket pkt;
av_log_set_level ( AV_LOG_DEBUG) ;
if ( src_filename == NULL || dst_filename == NULL ) {
av_log ( NULL , AV_LOG_ERROR, "src or dts file is null, plz check them!\n" ) ;
return - 1 ;
}
dst_fd = fopen ( dst_filename, "wb" ) ;
if ( ! dst_fd) {
av_log ( NULL , AV_LOG_DEBUG, "Could not open destination file %s\n" , dst_filename) ;
return - 1 ;
}
if ( ( err_code = avformat_open_input ( & fmt_ctx, src_filename, NULL , NULL ) ) < 0 ) {
av_strerror ( err_code, errors, 1024 ) ;
av_log ( NULL , AV_LOG_DEBUG, "Could not open source file: %s, %d(%s)\n" ,
src_filename,
err_code,
errors) ;
return - 1 ;
}
av_dump_format ( fmt_ctx, 0 , src_filename, 0 ) ;
av_init_packet ( & pkt) ;
pkt. data = NULL ;
pkt. size = 0 ;
video_stream_index = av_find_best_stream ( fmt_ctx, AVMEDIA_TYPE_VIDEO, - 1 , - 1 , NULL , 0 ) ;
if ( video_stream_index < 0 ) {
av_log ( NULL , AV_LOG_DEBUG, "Could not find %s stream in input file %s\n" ,
av_get_media_type_string ( AVMEDIA_TYPE_VIDEO) ,
src_filename) ;
return AVERROR ( EINVAL) ;
}
while ( av_read_frame ( fmt_ctx, & pkt) >= 0 ) {
if ( pkt. stream_index == video_stream_index) {
h264_mp4toannexb ( fmt_ctx, & pkt, dst_fd) ;
}
av_packet_unref ( & pkt) ;
}
avformat_close_input ( & fmt_ctx) ;
if ( dst_fd) {
fclose ( dst_fd) ;
}
return 0 ;
}
clang - g - o 6 _extra_video 6 _extra_video. c `pkg- config -- cflags -- libs libavutil libavformat`
. / 6 _extra_video
9、FFmpeg 将 MP4 转换为 FLV 格式
avfotmat_alloc_output_context2 ( )
avfotmat_free_context ( )
avfotmat_new_stream ( )
avcodec_parameters_copy ( )
avformat_write_header ( )
av_write_frame ( )
av_interleaved_write_frame ( )
av_write_trailer ( )
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
static void log_packet ( const AVFormatContext * fmt_ctx, const AVPacket * pkt, const char * tag) {
AVRational * time_base = & fmt_ctx-> streams[ pkt-> stream_index] -> time_base;
printf ( "%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n" ,
tag,
av_ts2str ( pkt-> pts) , av_ts2timestr ( pkt-> pts, time_base) ,
av_ts2str ( pkt-> dts) , av_ts2timestr ( pkt-> dts, time_base) ,
av_ts2str ( pkt-> duration) , av_ts2timestr ( pkt-> duration, time_base) ,
pkt-> stream_index) ;
}
int main ( int argc, char * * argv) {
AVOutputFormat * ofmt = NULL ;
AVFormatContext * ifmt_ctx = NULL , * ofmt_ctx = NULL ;
AVPacket pkt;
const char * in_filename, * out_filename;
int ret, i;
int stream_index = 0 ;
int * stream_mapping = NULL ;
int stream_mapping_size = 0 ;
if ( argc < 3 ) {
printf ( "usage: %s input output\n"
"API example program to remux a media file with libavformat and libavcodec.\n"
"The output format is guessed according to the file extension.\n"
"\n" , argv[ 0 ] ) ;
return 1 ;
}
in_filename = argv[ 1 ] ;
out_filename = argv[ 2 ] ;
if ( ( ret = avformat_open_input ( & ifmt_ctx, in_filename, 0 , 0 ) ) < 0 ) {
fprintf ( stderr , "Could not open input file '%s'" , in_filename) ;
goto end;
}
if ( ( ret = avformat_find_stream_info ( ifmt_ctx, 0 ) ) < 0 ) {
fprintf ( stderr , "Failed to retrieve input stream information" ) ;
goto end;
}
av_dump_format ( ifmt_ctx, 0 , in_filename, 0 ) ;
avformat_alloc_output_context2 ( & ofmt_ctx, NULL , NULL , out_filename) ;
if ( ! ofmt_ctx) {
fprintf ( stderr , "Could not create output context\n" ) ;
ret = AVERROR_UNKNOWN;
goto end;
}
stream_mapping_size = ifmt_ctx-> nb_streams;
stream_mapping = av_mallocz_array ( stream_mapping_size, sizeof ( * stream_mapping) ) ;
if ( ! stream_mapping) {
ret = AVERROR ( ENOMEM) ;
goto end;
}
ofmt = ofmt_ctx-> oformat;
for ( i = 0 ; i < ifmt_ctx-> nb_streams; i++ ) {
AVStream * out_stream;
AVStream * in_stream = ifmt_ctx-> streams[ i] ;
AVCodecParameters * in_codecpar = in_stream-> codecpar;
if ( in_codecpar-> codec_type != AVMEDIA_TYPE_AUDIO &&
in_codecpar-> codec_type != AVMEDIA_TYPE_VIDEO &&
in_codecpar-> codec_type != AVMEDIA_TYPE_SUBTITLE) {
stream_mapping[ i] = - 1 ;
continue ;
}
stream_mapping[ i] = stream_index++ ;
out_stream = avformat_new_stream ( ofmt_ctx, NULL ) ;
if ( ! out_stream) {
fprintf ( stderr , "Failed allocating output stream\n" ) ;
ret = AVERROR_UNKNOWN;
goto end;
}
ret = avcodec_parameters_copy ( out_stream-> codecpar, in_codecpar) ;
if ( ret < 0 ) {
fprintf ( stderr , "Failed to copy codec parameters\n" ) ;
goto end;
}
out_stream-> codecpar-> codec_tag = 0 ;
}
av_dump_format ( ofmt_ctx, 0 , out_filename, 1 ) ;
if ( ! ( ofmt-> flags & AVFMT_NOFILE) ) {
ret = avio_open ( & ofmt_ctx-> pb, out_filename, AVIO_FLAG_WRITE) ;
if ( ret < 0 ) {
fprintf ( stderr , "Could not open output file '%s'" , out_filename) ;
goto end;
}
}
ret = avformat_write_header ( ofmt_ctx, NULL ) ;
if ( ret < 0 ) {
fprintf ( stderr , "Error occurred when opening output file\n" ) ;
goto end;
}
while ( 1 ) {
AVStream * in_stream, * out_stream;
ret = av_read_frame ( ifmt_ctx, & pkt) ;
if ( ret < 0 )
break ;
in_stream = ifmt_ctx-> streams[ pkt. stream_index] ;
if ( pkt. stream_index >= stream_mapping_size ||
stream_mapping[ pkt. stream_index] < 0 ) {
av_packet_unref ( & pkt) ;
continue ;
}
pkt. stream_index = stream_mapping[ pkt. stream_index] ;
out_stream = ofmt_ctx-> streams[ pkt. stream_index] ;
log_packet ( ifmt_ctx, & pkt, "in" ) ;
pkt. pts = av_rescale_q_rnd ( pkt. pts, in_stream-> time_base, out_stream-> time_base,
AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) ;
pkt. dts = av_rescale_q_rnd ( pkt. dts, in_stream-> time_base, out_stream-> time_base,
AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) ;
pkt. duration = av_rescale_q ( pkt. duration, in_stream-> time_base, out_stream-> time_base) ;
pkt. pos = - 1 ;
log_packet ( ofmt_ctx, & pkt, "out" ) ;
ret = av_interleaved_write_frame ( ofmt_ctx, & pkt) ;
if ( ret < 0 ) {
fprintf ( stderr , "Error muxing packet\n" ) ;
break ;
}
av_packet_unref ( & pkt) ;
}
av_write_trailer ( ofmt_ctx) ;
end:
avformat_close_input ( & ifmt_ctx) ;
if ( ofmt_ctx && ! ( ofmt-> flags & AVFMT_NOFILE) )
avio_closep ( & ofmt_ctx-> pb) ;
avformat_free_context ( ofmt_ctx) ;
av_freep ( & stream_mapping) ;
if ( ret < 0 && ret != AVERROR_EOF) {
fprintf ( stderr , "Error occurred: %s\n" , av_err2str ( ret) ) ;
return 1 ;
}
return 0 ;
}
clang - g - o 7 _ff_mp4_muxing_flv 7 _ff_mp4_muxing_flv. c `pkg- config -- cflags -- libs libavutil libavformat`
. / 7 _ff_mp4_muxing_flv . / files/ sample. mp4 . / files/ sample. flv
10、FFmpeg 从 MP4 截取一段视频
av_seek_frame ( )
#include <stdlib.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
static void log_packet ( const AVFormatContext * fmt_ctx, const AVPacket * pkt, const char * tag) {
AVRational * time_base = & fmt_ctx-> streams[ pkt-> stream_index] -> time_base;
printf ( "%s: pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n" ,
tag,
av_ts2str ( pkt-> pts) , av_ts2timestr ( pkt-> pts, time_base) ,
av_ts2str ( pkt-> dts) , av_ts2timestr ( pkt-> dts, time_base) ,
av_ts2str ( pkt-> duration) , av_ts2timestr ( pkt-> duration, time_base) ,
pkt-> stream_index) ;
}
int cut_video ( double from_seconds, double end_seconds, const char * in_filename, const char * out_filename) {
AVOutputFormat * ofmt = NULL ;
AVFormatContext * ifmt_ctx = NULL , * ofmt_ctx = NULL ;
AVPacket pkt;
int ret, i;
if ( ( ret = avformat_open_input ( & ifmt_ctx, in_filename, 0 , 0 ) ) < 0 ) {
fprintf ( stderr , "Could not open input file '%s'" , in_filename) ;
goto end;
}
if ( ( ret = avformat_find_stream_info ( ifmt_ctx, 0 ) ) < 0 ) {
fprintf ( stderr , "Failed to retrieve input stream information" ) ;
goto end;
}
av_dump_format ( ifmt_ctx, 0 , in_filename, 0 ) ;
avformat_alloc_output_context2 ( & ofmt_ctx, NULL , NULL , out_filename) ;
if ( ! ofmt_ctx) {
fprintf ( stderr , "Could not create output context\n" ) ;
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt = ofmt_ctx-> oformat;
for ( i = 0 ; i < ifmt_ctx-> nb_streams; i++ ) {
AVStream * in_stream = ifmt_ctx-> streams[ i] ;
AVStream * out_stream = avformat_new_stream ( ofmt_ctx, NULL ) ;
if ( ! out_stream) {
fprintf ( stderr , "Failed allocating output stream\n" ) ;
ret = AVERROR_UNKNOWN;
goto end;
}
ret = avcodec_parameters_copy ( out_stream-> codecpar, in_stream-> codecpar) ;
if ( ret < 0 ) {
fprintf ( stderr , "Failed to copy context from input to output stream codec context\n" ) ;
goto end;
}
out_stream-> codecpar-> codec_tag = 0 ;
}
av_dump_format ( ofmt_ctx, 0 , out_filename, 1 ) ;
if ( ! ( ofmt-> flags & AVFMT_NOFILE) ) {
ret = avio_open ( & ofmt_ctx-> pb, out_filename, AVIO_FLAG_WRITE) ;
if ( ret < 0 ) {
fprintf ( stderr , "Could not open output file '%s'" , out_filename) ;
goto end;
}
}
ret = avformat_write_header ( ofmt_ctx, NULL ) ;
if ( ret < 0 ) {
fprintf ( stderr , "Error occurred when opening output file\n" ) ;
goto end;
}
ret = av_seek_frame ( ifmt_ctx, - 1 , from_seconds * AV_TIME_BASE, AVSEEK_FLAG_ANY) ;
if ( ret < 0 ) {
fprintf ( stderr , "Error seek\n" ) ;
goto end;
}
int64_t * dts_start_from = malloc ( sizeof ( int64_t) * ifmt_ctx-> nb_streams) ;
memset ( dts_start_from, 0 , sizeof ( int64_t) * ifmt_ctx-> nb_streams) ;
int64_t * pts_start_from = malloc ( sizeof ( int64_t) * ifmt_ctx-> nb_streams) ;
memset ( pts_start_from, 0 , sizeof ( int64_t) * ifmt_ctx-> nb_streams) ;
while ( 1 ) {
AVStream * in_stream, * out_stream;
ret = av_read_frame ( ifmt_ctx, & pkt) ;
if ( ret < 0 )
break ;
in_stream = ifmt_ctx-> streams[ pkt. stream_index] ;
out_stream = ofmt_ctx-> streams[ pkt. stream_index] ;
log_packet ( ifmt_ctx, & pkt, "in" ) ;
if ( av_q2d ( in_stream-> time_base) * pkt. pts > end_seconds) {
av_packet_unref ( & pkt) ;
break ;
}
if ( dts_start_from[ pkt. stream_index] == 0 ) {
dts_start_from[ pkt. stream_index] = pkt. dts;
printf ( "dts_start_from: %s\n" , av_ts2str ( dts_start_from[ pkt. stream_index] ) ) ;
}
if ( pts_start_from[ pkt. stream_index] == 0 ) {
pts_start_from[ pkt. stream_index] = pkt. pts;
printf ( "pts_start_from: %s\n" , av_ts2str ( pts_start_from[ pkt. stream_index] ) ) ;
}
pkt. pts = av_rescale_q_rnd ( pkt. pts - pts_start_from[ pkt. stream_index] , in_stream-> time_base,
out_stream-> time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) ;
pkt. dts = av_rescale_q_rnd ( pkt. dts - dts_start_from[ pkt. stream_index] , in_stream-> time_base,
out_stream-> time_base, AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX) ;
if ( pkt. pts < 0 ) {
pkt. pts = 0 ;
}
if ( pkt. dts < 0 ) {
pkt. dts = 0 ;
}
pkt. duration = ( int ) av_rescale_q ( ( int64_t) pkt. duration, in_stream-> time_base, out_stream-> time_base) ;
pkt. pos = - 1 ;
log_packet ( ofmt_ctx, & pkt, "out" ) ;
printf ( "\n" ) ;
ret = av_interleaved_write_frame ( ofmt_ctx, & pkt) ;
if ( ret < 0 ) {
fprintf ( stderr , "Error muxing packet\n" ) ;
break ;
}
av_packet_unref ( & pkt) ;
}
free ( dts_start_from) ;
free ( pts_start_from) ;
av_write_trailer ( ofmt_ctx) ;
end:
avformat_close_input ( & ifmt_ctx) ;
if ( ofmt_ctx && ! ( ofmt-> flags & AVFMT_NOFILE) )
avio_closep ( & ofmt_ctx-> pb) ;
avformat_free_context ( ofmt_ctx) ;
if ( ret < 0 && ret != AVERROR_EOF) {
fprintf ( stderr , "Error occurred: %s\n" , av_err2str ( ret) ) ;
return 1 ;
}
return 0 ;
}
int main ( int argc, char * argv[ ] ) {
if ( argc < 5 ) {
fprintf ( stderr , "Usage: command startime, endtime, srcfile, outfile" ) ;
return - 1 ;
}
double startime = atoi ( argv[ 1 ] ) ;
double endtime = atoi ( argv[ 2 ] ) ;
cut_video ( startime, endtime, argv[ 3 ] , argv[ 4 ] ) ;
return 0 ;
}
clang - g - o 8 _ff_cut_video 8 _ff_cut_video. c `pkg- config -- cflags -- libs libavutil libavformat`
. / 8 _ff_cut_video 0 5 . / files/ sample. mp4 . / files/ sample2. mp4
11、实现一个简单的抖音业务功能
(1 )将两个媒体文件中分别抽取音频与视频轨;
(2 )将音频与视频合成一个新的文件;
(3 )对音频与视频轨进行裁剪。