来源:http://blog.sina.com.cn/s/blog_62a8419a01016exv.html

本文是作者在使用ffmpeg sdk开发过程中的实际经验,现在与大家分享,欢迎学习交流。

FFMPEG SDK 开发介绍

1.简介:
   
ffmpeg是一套可以用来记录、转换数字音频、视频,并能将其转化为流的开源计算机程序。
使用ffmpeg能够完成如下功能:parse,demux,decode,filter(preprocessing),encode,mux,stream和player等.

2.下载和编译:

下载地址:  http://ffmpeg.org/download.html

编译:
      
1)windows平台static library/shared library,
编译工具:mingw-gcc或者在linux平台下交叉编译(推荐)
      
2)linux平台static library/shared library, 编译工具:gcc

模块:
       
libavcodec    -
编码解码器
       
libavdevice   - 输入输出设备的支持
       
libavfilter   - 视音频滤镜支持
       
libavformat   - 视音频等格式的解析
       
libavutil    
- 工具库
       
libpostproc   - 后期效果处理
       
libswscale    -
图像颜色、尺寸转换
    
3.SDK介绍和开发(基于ffmpeg 0.8 sdk)
   
ffmpeg每部分功能都采用plugin的方式,使用统一的接口调用,这样就能够非常方便的使用和扩展。
   
plugin分为几种:muxer,demuxer,protocol,hwaccel,encoder,decoder,parser,bitstream,filter,...

因此在使用SDK的时候第一步就是注册plugin
    
   
avcodec_register_all()  : 注册
hwaccel,encoder,decoder,parser,bitstream
   
av_register_all()      
: 注册 muxer,demuxer,protocol
   
avfilter_register_all() : 注册 滤镜filter
    
   
下面根据不同的应用场景,给出主要的代码示例(仅是代码片断,不一定能编译通过):
    
   
1)如何获取媒体文件的信息(Parser):
    // 参考V3代码:
interface IFileDecoder, media/impl/filedecoderimpl.cpp
    
    {
       
av_register_all();
       
AVFormatContext * pFormatCtx = NULL;
       
int err = 0;
       
const char *fileName = "c:\\test.mp4";
       
err = av_open_input_file(&pFormatCtx, fileName, NULL, 0,
NULL);
       
if(err != 0)
       
{
           
// break ;
       
}
       
err = av_find_stream_info(pFormatCtx);
       
if(err < 0)
       
{
           
// break ;
       
}
       
for(uint32_t i = 0; i <
pFormatCtx->nb_streams; i ++)
       
{
           
// stream 结构数据
           
AVStream *pStream = pFormatCtx->streams[i];
           
// 帧率信息
           
AVRational frameRate = pStream->r_frame_rate;
           
// 时间单位比率
           
AVRational timeBase = pStream->time_base;
           
// stream duration
           
int64_t duration = pStream->duration;
          
 
           
// 获取Codec数据结构
           
AVCodecContext *pCodecCtx = pStream->codec;
           
AVMediaType codecType = pCodecCtx->codec_type;

CodecID codecId = pCodecCtx->codec_id;

if(codecType == AVMEDIA_TYPE_VIDEO)
           
{
               
// 获取Video基本信息
               
int width = pCodecCtx->width;
               
int height = pCodecCtx->height;
               
PixelFormat pixelFormat = pCodecCtx->pix_fmt;
           
}
           
else if(codecType == AVMEDIA_TYPE_AUDIO)
           
{
               
// 获取Audio基本信息
               
int channels = pCodecCtx->channels;
               
int sample_rate = pCodecCtx->sample_rate;
               
AVSampleFormat sampleFmt = pCodecCtx->sample_fmt;
           
}
       
}
       
// 释放
       
if(pFormatCtx != NULL)
       
{
           
av_close_input_file(pFormatCtx);
           
pFormatCtx = NULL;
       
}    
    }
    
   
2)读取sample数据(Read raw sample不解码)
    // 参考V3代码:
interface IFileDecoder, media/impl/filedecoderimpl.cpp

{
       
// 参考Parser代码
       
// av_register_all();
       
// AVFormatContext * pFormatCtx = NULL;
       
// err = av_open_input_file(&pFormatCtx, fileName, NULL, 0,
NULL);
    
       
AVPacket packet;
       
av_init_packet(&packet);
       
int ret = av_read_frame(pFormatCtx, &packet);
       
if(ret >= 0)
       
{
           
int streamIndex = packet.stream_index;
           
AVStream *pStream = pFormatCtx->streams[streamIndex];
           
AVCodecContext *pCodecCtx = pStream->codec;
           
// 计算timestamp
    
           
// 转换时间到1/1000000秒
           
AVRational time_base;
           
time_base.num = 1;
           
time_base.den = 1000000;
          
 
  
   
   
 //
25.0    
1/25,  
29.97   
1001/30000
  
   
   
 
           
// 获取 dts/pts
           
const int64_t dts = av_rescale_q(packet.dts, pStream->time_base,
time_base);
           
const int64_t pts = av_rescale_q(packet.pts, pStream->time_base,
time_base);
           
uint8_t *data = packet.data;
           
int size = packet.size;
           
bool isKey = ((packet.flags & AV_PKT_FLAG_KEY) ==
AV_PKT_FLAG_KEY);  
 
       
}
       
av_free_packet(&packet);      
 
    }
    
   
3)解码sample(Video ES=>YUV/RGB,  Audio
ES=>PCM)
    // 参考V3代码:
interface IVideoDecoder/IAudioDecoder,
media/impl/videodecoderimpl.cpp/audiodecoderimpl.cpp
    {
       
// 参考Parser,Read raw sample代码
      
 
       
// AVMediaType codecType = pCodecCtx->codec_type;
       
AVMediaType codecType = AVMEDIA_TYPE_VIDEO;
       
// CodecId codecId = pCodecCtx->codec_id;
       
CodecId codecId = CODEC_ID_H264;
      
 
       
// 通过Codec ID查找解码器
       
AVCodec *pCodec = avcodec_find_decoder(codecId);
       
// 分配codec关联结构
       
AVCodecContext *pCodecCtx = avcodec_alloc_context();

// 设置一些必要的信息
       
pCodecCtx->codec_type = AVMEDIA_TYPE_VIDEO /
AVMEDIA_TYPE_AUDIO;
       
pCodecCtx->codec_id   =
codecId;

if(pCodec->capabilities & CODEC_CAP_TRUNCATED)
           
pCodecCtx->flags |= CODEC_FLAG_TRUNCATED;

// 在open codec时要加锁,否则多个codec同时打开时时会出现错误
       
gMutexFFmpeg.lock();      
 
       
// 打开Codec
       
avcodec_open(pCodecCtx,
pCodec);      
 
       
gMutexFFmpeg.unlock();
      
 
       
if(codecType == AVMEDIA_TYPE_VIDEO)
       
{
           
AVFrame *pSrcFrame = avcodec_alloc_frame();
           
AVFrame *pDstFrame = avcodec_alloc_frame();
          
 
           
// 因为内存的原因,所以需要多分配一些数据, FF_INPUT_BUFFER_PADDING_SIZE
           
uint8_t *data = ...;
           
int size = ...;
    
           
while(size > 0))
           
{
               
AVPacket pkt;
               
av_init_packet(&pkt);
               
pkt.data  = data;
               
pkt.size  = size;

int frameFinished = 0;
               
int bytesDecoded = avcodec_decode_video2(pCodecCtx, pSrcFrame,
&frameFinished, &pkt);
               
if(bytesDecoded > 0)
               
{
                   
data += bytesDecoded;
                   
size -= bytesDecoded;
               
}
               
if(frameFinished)
               
{
                   
int numBytes = avpicture_get_size(pCodecCtx->pix_fmt,
pCodecCtx->width, pCodecCtx->height);
                   
uint8_t *pBuffer = new uint8_t[numBytes];
                   
avpicture_fill((AVPicture *)pDstFrame, pBuffer,
pCodecCtx->pix_fmt, pCodecCtx->width,
pCodecCtx->height);
                   
av_picture_copy((AVPicture *)pDstFrame, (AVPicture *)pSrcFrame,
pCodecCtx->pix_fmt, pCodecCtx->width,
pCodecCtx->height);
                  
 
                   
// pBuffer/numBytes/pCodecCtx->pix_fmt : YUV/RGB数据
                   
delete
[]pBuffer;                  
 
               
}
              
 
               
if(bytesDecoded < 0)
                   
break ;
           
}
           
av_free(pSrcFrame);
           
av_free(pDstFrame);
       
}
       
else if(codecType == AVMEDIA_TYPE_AUDIO)
       
{
           
// 分配解码内存空间
           
uint8_t *pBuffer = new uint8_t[AVCODEC_MAX_AUDIO_FRAME_SIZE];
    
           
// 因为内存的原因,所以需要多分配一些数据, FF_INPUT_BUFFER_PADDING_SIZE
           
uint8_t *data = ...;
           
int size = ...;
    
           
while(size > 0)
           
{
               
AVPacket pkt;
               
av_init_packet(&pkt);
               
pkt.data  = data;
               
pkt.size  = size;
              
 
               
int outSize = AVCODEC_MAX_AUDIO_FRAME_SIZE;
               
int bytesDecoded = avcodec_decode_audio3(pCodecCtx, (int16_t
*)pBuffer, &outSize, &pkt);
               
if(bytesDecoded > 0)
               
{
                   
data += bytesDecoded;
                   
size -= bytesDecoded;
               
}
               
if((bytesDecoded >= 0) && (outSize > 0))
               
{
                   
// pBuffer/outSize : PCM数据
                   
// 格式
                   
// pCodecCtx->channels;
                   
// pCodecCtx->sample_fmt;
                   
// pCodecCtx->sample_rate;
               
}              
 
           
}          
 
       
}
      
 
       
gMutexFFmpeg.lock();      
 
       
// 关闭和释放
       
avcodec_close(pCodecCtx);
       
gMutexFFmpeg.unlock();
       
av_free(pCodecCtx);
    }
    
   
4)视音频编码(YUV/RGB=>Video ES, PCM=>Audio ES)
    // 参考V3代码:
media/videoencoder.cpp/audioencoder.cpp
    {
       
// video encode
       
avcodec_register_all();
       
// 查找编码器
       
AVCodec *avCodec =
avcodec_find_encoder((CodecID)mConfig.codec);
       
AVCodecContext *codecCtx = avcodec_alloc_context();
       
codecCtx->codec_type   
= AVMEDIA_TYPE_VIDEO;
       
codecCtx->codec_id     
= (CodecID)mConfig.codec;
       
codecCtx->width        
= mOutFormat.width;
       
codecCtx->height       
= mOutFormat.height;
       
codecCtx->pix_fmt      
= (PixelFormat)mOutFormat.pixelFormat;

uint32 num = 0;
       
uint32 den = 0;
       
SampleUtil::FPS2Timescale(mOutFormat.frameRate, num, den);
       
codecCtx->time_base.num = num;
       
codecCtx->time_base.den =
den;      
 
       
codecCtx->bit_rate     
= mConfig.bitRate*1000;
       
codecCtx->max_b_frames  = 0;
       
codecCtx->gop_size     
= 100;
       
if(codecCtx->codec_id == CODEC_ID_MPEG1VIDEO)
       
{
           
codecCtx->mb_decision = FF_MB_DECISION_RD;
       
}
       
else
       
{
           
codecCtx->mb_decision = FF_MB_DECISION_RD;
       
}
      
 
       
avcodec_open(codecCtx, avCodec);
       
// 分配编码后的内存,分配为1MB
       
mOutputBuffer.resize(1*1024*1024);
      
 
       
AVFrame *pSrcFrame = avcodec_alloc_frame();
      
 
       
avcodec_get_frame_defaults(pSrcFrame);
       
int ret = avpicture_fill((AVPicture *)pSrcFrame, (uint8_t
*)inData.data, (PixelFormat)mOutFormat.pixelFormat,
mOutFormat.width, mOutFormat.height);

AVRational time_base;
       
time_base.num = 1;
       
time_base.den = 1000000;
       
pSrcFrame->pts = av_rescale_q(inData.dts, time_base,
codecCtx->time_base);
      
 
       
int bytesWritten = avcodec_encode_video(codecCtx, (uint8
*)mOutputBuffer.data(), mOutputBuffer.size(),
           
isEmpty ? NULL : pSrcFrame);

outData.data  = (char
*)mOutputBuffer.data();
       
outData.size  = bytesWritten;
       
outData.isKey = (mCodecCtx->coded_frame->key_frame !=
0);
    
    
       
av_free(pSrcFrame);
       
avcodec_close(codecCtx);
       
av_free(codecCtx);
      
 
      
 
       
// audio encode请看audioencoder.cpp
文件      
 
    }
    
   
5)图像格式转换(YUV/RGB <=> YUV/RGB & Resize)
    // 参考代码:
media/imageconverter.cpp
    {
       
SwsContext *pSwsCtx = NULL;

// resize 算法
       
int swsFlags  = SWS_LANCZOS; //
SWS_FAST_BILINEAR;
       
// 初始化
       
pSwsCtx = sws_getCachedContext(NULL, srcWidth, srcHeight,
srcFmt,
           
dstWidth, dstHeight, dstFmt, swsFlags, NULL, NULL, NULL);
      
 
       
// 设置数据到结构 AVPicture
       
AVPicture avSrcPic;
       
AVPicture avDstPic;
       
memset(&avSrcPic, 0, sizeof(avSrcPic));
       
memset(&avDstPic, 0, sizeof(avDstPic));
       
int dstRet = avpicture_fill(&avDstPic, (uint8_t *)pDstBuffer,
dstFmt, dstWidth, dstHeight);
    
 
  
   {
       
// pSrcBuffer - 源数据
       
// pDstBuffer - 目标数据
       
int srcRet = avpicture_fill(&avSrcPic, (uint8_t *)pSrcBuffer,
srcFmt, srcWidth, srcHeight);

// 执行转换
       
sws_scale(pSwsCtx, avSrcPic.data, avSrcPic.linesize, 0,
abs(srcHeight), avDstPic.data, avDstPic.linesize);
      
}
  
    
       
// 释放
       
sws_freeContext(pSwsCtx);
    }
    
   
6)封装格式(Muxer, .mp4/.avi/.mkv...)
    // 参考代码:
interface IFileWriter, media/impl/filewriterimpl.cpp
    {
       
av_register_all();

AVFormatContext * pFormatCtx;
       
avformat_alloc_output_context2(&pFormatCtx, NULL, "mp4",
"c:\\out.mp4");
      
 
       
{
           
// new video stream
           
AVStream * avStream = av_new_stream(pFormatCtx,
pFormatCtx->nb_streams;
           
avcodec_get_context_defaults3(avStream->codec, NULL);

AVCodecContext *codecCtx = avStream->codec;
           
codecCtx->codec_id      
= (CodecID)format->codecId;
           
codecCtx->codec_type    
= AVMEDIA_TYPE_VIDEO;
           
codecCtx->width         
= format->width;
           
codecCtx->height        
= format->height;
           
codecCtx->bit_rate      
= 800000;
           
uint32 num = 0;
           
uint32 den = 0;
           
SampleUtil::FPS2Timescale(format->frameRate, num, den);
           
codecCtx->time_base.num  = num;
           
codecCtx->time_base.den  = den;
           
av_set_pts_info(streamInfo->avStream, 64, num, den);
          
 
           
if(pFormatCtx->oformat->flags & AVFMT_GLOBALHEADER)
           
{
               
codecCtx->flags |= CODEC_FLAG_GLOBAL_HEADER;
           
}
           
switch(codecCtx->codec_id)
           
{
           
case CODEC_ID_H264:
               
{
                   
AVBitStreamFilterContext * avFilter =
av_bitstream_filter_init("h264_mp4toannexb");
               
}
               
break ;
           
case CODEC_ID_AAC:
               
{
                   
codecCtx->frame_size = 1024;
                   
AVBitStreamFilterContext * avFilter =
av_bitstream_filter_init("aac_adtstoasc");
               
}
               
break ;
           
}
           
// 设置解码相关数据, 比如H264要设置:SPS & PPS
           
codecCtx->extradata_size = ;// size;
           
codecCtx->extradata     
= ;// (uint8_t *)av_malloc(size +
FF_INPUT_BUFFER_PADDING_SIZE);
       
}
       
{
           
// new stream
           
AVStream * avStream = av_new_stream(pFormatCtx,
pFormatCtx->nb_streams;
           
avcodec_get_context_defaults3(avStream->codec, NULL);
       
}
      
 
       
err = av_set_parameters(pFormatCtx, NULL);
       
// 以写的方式打开文件
       
err = avio_open(&pFormatCtx->pb, "c:\\out.mp4",
AVIO_FLAG_WRITE);

// 写文件头信息
       
err = av_write_header(pFormatCtx);
      
 
       
{
           
const AVRational in_time_base = { 1, 1000000 };
           
AVRational out_time_base = avStream->time_base;

AVPacket pkt = { 0 };
           
av_init_packet(&pkt);
          
 
           
pkt.stream_index = streamId; // 流的id
           
pkt.data  = ;//(uint8_t
*)mediaSample->data();
           
pkt.size  = ;//mediaSample->size();
           
// 转换dts/pts时间单位 
1/1000000=>avStream->time_base
           
pkt.dts   =
av_rescale_q(mediaSample->dts(), in_time_base,
out_time_base);
           
pkt.pts   =
av_rescale_q(mediaSample->pts(), in_time_base,
out_time_base);
           
pkt.flags = mediaSample->isKey() ? AV_PKT_FLAG_KEY : 0;

// 写入一帧数据
           
int err = av_interleaved_write_frame(pFormatCtx, &pkt);

av_free_packet(&pkt);          
 
       
}
              
 
       
// 写文件尾信息
       
av_write_trailer(pFormatCtx);
      
 
       
// 释放
       
// av_bitstream_filter_close(avFilter);
       
avio_close(pFormatCtx->pb);
       
avformat_free_context(pFormatCtx);
    }
    
   
7)滤镜filter的使用(crop, resize, deinterlace, drawtext, overlay, vflip,
...)
   
通过搭建若干个filter可以对视音频进行一系列的处理.
      
 
    
a).Simple filtergraphs:
   
 
        
reencode filter graph:
        
_________                       
__________             
______________
       
|        
|                     
|         
|           
|             
|
       
| decoded |  simple filtergraph 
| filtered | 
encoder   | encoded data |
       
| frames  | -------------------> |
frames   | ---------> |
packets     
|
       
|_________|                     
|__________|           
|______________|

filter graph:
        
_______       
_____________       
_______       
_____       
________
       
|      
|     
|            
|     
|      
|     
|    
|     
|       
|
       
| input | ---> | deinterlace | ---> | scale | ---> | fps |
---> | output |
       
|_______|     
|_____________|     
|_______|     
|_____|     
|________|
      
 
      
 
  
   
   
   
 int ret =
av_vsink_buffer_get_video_buffer_ref(mBufferDstCtx, &picRef,
0);
request_frame

start_frame
draw_slice
end_frame
  
   
 
  
   
 
    b).Complex
filtergraphs:
        
_________
       
|        
|
       
| input 0
|\                   
__________
       
|_________|
\                 
|         
|
                    
\  
_________    /|
output 0 |
                     
\
|        
|  / |__________|
        
_________    
\| complex | /
       
|        
|    
|        
|/
       
| input 1 |---->| filter  |\
       
|_________|    
|        
| \   __________
                      
/| graph   |  \
|         
|
                     
/
|        
|   \| output 1 |
        
_________   / 
|_________|   
|__________|
       
|        
| /
       
| input 2 |/
       
|_________|
      
 
    
    V3组件中实现的
interface IVideoPreprocess代码示例:
   
代码文件:media/impl/videopreprocessimpl.cpp
    
    我们搭建的filter
graph:
                                                                                        
/1-->pad----\
       
input-->deinterlace-->fps-->logo
remove-->color-->image
overlaps-->crop-->resize<-0----------->output
                                                                                        
\2-->crop---/
                                                                                           
 
       
{
           
avcodec_register_all();
           
avfilter_register_all();
          
 
           
AVFilterGraph * pFilterGraph = NULL;
           
AVFilterContext * pBufferSrcCtx = NULL;
           
AVFilterContext * pBufferDstCtx = NULL;
          
 
           
AVFrame * pSrcFrame   =
avcodec_alloc_frame();
           
AVFrame * pSinkFrame  =
avcodec_alloc_frame();
           
AVFrame * pDstFrame   =
avcodec_alloc_frame();

// 设定输出格式列表,我们仅支持PIX_FMT_YUV420P
           
PixelFormat pix_fmts[] = { PIX_FMT_YUV420P, PIX_FMT_NONE };
           
char args[512];
          
 
           
AVFilterContext *lastFilterCtx = NULL;
          
 
           
// 我们使用到的filter,其中"nl_"开头的是我们自己写的filter
           
// 输入buffer filter
           
AVFilter
*bufferFilter    
= avfilter_get_by_name("buffer");
           
// deinterlace filter, 目前使用yadif filter
           
AVFilter
*yadifFilter     
= avfilter_get_by_name("yadif");
           
// 我们自己实现的fps转换filter
           
AVFilter
*fpsFilter       
= avfilter_get_by_name("nl_fps");
           
// 我们自己实现的遮logo的filter,支持多个,动态设置,能够设定区间范围
           
AVFilter
*delogosFilter   
= avfilter_get_by_name("nl_delogos");
           
// 我们自己实现的调节对比度和亮度的filter
           
AVFilter
*colorFilter     
= avfilter_get_by_name("nl_color");
           
// 我们自己实现的叠加图片的filter,支持多个,动态设置,能够设定区间范围
           
AVFilter *overlaysFilter   =
avfilter_get_by_name("nl_overlays");
           
// crop filter
           
AVFilter
*cropFilter      
= avfilter_get_by_name("crop");
           
// resize filter
           
AVFilter
*resizeFilter    
= avfilter_get_by_name("scale");
           
// 图像扩展filter,可以在图像边界填充特定的颜色
           
AVFilter
*padFilter       
= avfilter_get_by_name("pad");
           
// 输出buffer filter
           
AVFilter *buffersinkFilter =
avfilter_get_by_name("buffersink");

// 创建graph
           
pFilterGraph = avfilter_graph_alloc();

// 开始创建filter
          
 
           
AVRational tb  = { 1, 1000000 };
           
AVRational sar = { 0, 1 };
           
// 计算图像宽度比
           
av_reduce(&sar.num, &sar.den, mConfig.width,
mConfig.height, 1000*1000);

// 设定 buffer filter的参数
           
//
w:h:pixfmt:time_base.num:time_base.den:sample_aspect_ratio.num:sample_aspect_ratio.den:sws_param

sprintf(args, "%d:%d:%d:%d:%d:%d:%d",
               
mConfig.width, mConfig.height, mConfig.pixelFormat, tb.num, tb.den,
sar.num, sar.den);

// input filter
           
err =
avfilter_graph_create_filter(&pBufferSrcCtx, 
bufferFilter,  "in", args, NULL,
pFilterGraph);
           
// 记录前一个filter context
           
lastFilterCtx = pBufferSrcCtx;
      
 
           
// 如果需要 deinterlace,则创建 yadif filter,同时和前一个filter进行连接
           
// deinterlace : yadif
           
if(mConfig.deinterlace > 0)
           
{
               
if(yadifFilter == NULL)
                   
break ;

// yadif filter的参数
               
// mode:parity
               
sprintf(args, "%d:%d", 0, -1);

// 创建filter,同时加入到graph
               
AVFilterContext *deinterlaceCtx = NULL;
               
err =
avfilter_graph_create_filter(&deinterlaceCtx, 
yadifFilter, "yadif", args, NULL, pFilterGraph);
               
if(err < 0)
                   
break ;

// 和前一个filter进行连接
               
err = avfilter_link(lastFilterCtx, 0, deinterlaceCtx, 0);
               
if(err < 0)
                   
break ;

lastFilterCtx = deinterlaceCtx;
           
}
           
// ... 中间略过
                  
 
           
// 创建output filter
           
err = avfilter_graph_create_filter(&pBufferDstCtx,
buffersinkFilter, "out", NULL, pix_fmts, pFilterGraph);
           
if(err < 0)
               
break ;
   
 
           
// 和前一个filter进行连接
           
err = avfilter_link(lastFilterCtx, 0, pBufferDstCtx, 0);
           
if(err < 0)
               
break ;
              
 
           
// 配置 graph
           
err = avfilter_graph_config(pFilterGraph, NULL);

// 把输入frame填充到结构AVFrame
           
avpicture_fill((AVPicture *)pSrcFrame, (uint8_t
*)inMediaSample->data(),
               
(PixelFormat)mConfig.pixelFormat, mConfig.width,
mConfig.height);
           
pSrcFrame->width  = mConfig.width;
           
pSrcFrame->height = mConfig.height;
           
pSrcFrame->format = mConfig.pixelFormat;
           
pSrcFrame->pts = inMediaSample->dts();

// 开始写input写入frame
           
ret = av_vsrc_buffer_add_frame(pBufferSrcCtx, pSrcFrame,
AV_VSRC_BUF_FLAG_OVERWRITE);
          
 
          
 
           
// 从输出filter查看输入是否可以获取数据,返回可获取的数目
           
int count = avfilter_poll_frame(pBufferDstCtx->inputs[0]);
           
if(count > 0)
           
{
               
AVFilterBufferRef *picRef = NULL;
               
// 从输出filter中获取结果
               
int ret = av_vsink_buffer_get_video_buffer_ref(pBufferDstCtx,
&picRef, 0);
               
if(picRef != NULL)
               
{
                   
// 转换AVFilterBufferRef到AVFrame
                   
avfilter_fill_frame_from_video_buffer_ref(pSinkFrame,
picRef);
                   
pSinkFrame->format = picRef->format;
                   
pSinkFrame->width  =
picRef->video->w;
                   
pSinkFrame->height = picRef->video->h;
                  
 
                   
const int numBytes =
avpicture_get_size((PixelFormat)pSinkFrame->format,
pSinkFrame->width, pSinkFrame->height);
                   
// 转换时间单位
                   
AVRational tb  = { 1, 1000000 };
                   
const int64 dts = av_rescale_q(picRef->pts,
mBufferDstCtx->inputs[0]->time_base, tb);
                   
// 获取图像数据
                   
avpicture_fill((AVPicture *)pDstFrame, (uint8_t
*)mediaSample->data(),
                       
(PixelFormat)pSinkFrame->format, pSinkFrame->width,
pSinkFrame->height);

av_picture_copy((AVPicture *)pDstFrame, (AVPicture
*)pSinkFrame,
                       
(PixelFormat)pSinkFrame->format, pSinkFrame->width,
pSinkFrame->height);                      
 
                  
 
                   
// 释放buffer计数器
                   
avfilter_unref_buffer(picRef);
               
}
           
}
       
}

更多文章,请访问我的个人网站 : http://www.codelive.cn/

FFMPEG SDK 开发介绍(原创)的更多相关文章

  1. FFmpeg SDK开发模型之中的一个:解码器

    简单介绍 本例解说了怎样使用ffmpeg SDK解码媒体文件: 參考源代码是ffmpeg 自带的apiexample.c 一.源代码#include <stdlib.h>#include ...

  2. 基于FFMPEG SDK流媒体开发1---解码媒体文件流信息

    近期项目涉及到流媒体等开发,因为有过开发经验深知其难度所在,没办法仅仅能又一次拾起,最新版的SDK被改的一塌糊涂,只是大体的开发思路都是一样的,看多少书查多少资料都无用,一步一步的编写代码 才是学好的 ...

  3. FFMPEG SDK流媒体开发2---分离.mp4等输入流音视频而且进行解码输出

    对于FFMPEG SDK  提供的Demuxing 为我们实现多路复用  提供了非常多方便,以下的案案例 实现的是 分离一个媒体文件的音频 视频流 而且解码输出 到  不同的文件里. 对于音频被还原回 ...

  4. Kinect for Windows SDK开发学习相关资源

    Kinect for Windows SDK(K4W)将Kinect的体感操作带到了平常的应用学习中,提供了一种不同于传统的鼠标,键盘及触摸的无接触的交互方式,在某种程度上实现了自然交互界面的理想,即 ...

  5. TortoiseSVN安装以及淘宝 TAE SDK 开发环境的搭建

    一.TortoiseSVN 的下载和安装 1.进入TortoiseSVN 官网下载地址http://tortoisesvn.net/downloads.html,根据自己的操作系统位数下载相应最新版本 ...

  6. Kinect for Windows SDK开发入门(一):开发环境配置

    [译]Kinect for Windows SDK开发入门(一):开发环境配置 前几天无意中看到微软发布了Kinect for windows sensor,进去看了一下Kinect应用的例子,发现K ...

  7. Kinect for Windows SDK开发入门(15):进阶指引 下

    Kinect for Windows SDK开发入门(十五):进阶指引 下 上一篇文章介绍了Kinect for Windows SDK进阶开发需要了解的一些内容,包括影像处理Coding4Fun K ...

  8. cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发

     cocos2d-x游戏开发实战原创视频讲座系列1之2048游戏开发 的产生 视持续更新中.... 视频存放地址例如以下:http://ipd.pps.tv/user/1058663622     ...

  9. 插件化技术在安卓sdk开发中实际应用

    笔者从 2016 年初就因为公司业务需求转战 android sdk 开发, 应用插件化技术将公司 android sdk 重新翻版.先来说说需求. 由于笔者所在一家创业公司, android sdk ...

随机推荐

  1. Andriod Studio安装及使用

    创建Andriod项目 1.下载最新版的Andriod studio 2.在 Welcome to Android Studio 窗口中,点击 Start a new Android Studio p ...

  2. 排序算法-桶排序(Java)

    package com.rao.sort; import java.util.*; /** * @author Srao * @className BucketSort * @date 2019/12 ...

  3. java spring框架的定时任务

    由于测试的原因,最近有接触java spring  @Scheduled的定时任务,当时还以为配置起来表达式和crontab是完全一样的,没想到还有些许不一样. 在spring中,一个cron表达式至 ...

  4. First Chance Exception是什么?

    是否调试过应用程序并在输出窗口中看到有关“First Chance”异常的消息?有没有想过: 什么是First Chance Exception? 第一次机会异常是否意味着我的代码中存在问题? 在调试 ...

  5. ESA2GJK1DH1K基础篇: 阿里云物联网平台: 测试MQTT连接阿里云物联网平台

    前言 这节看一下在阿里云上实现MQTT通信是个怎样的流程 看了很多网上的教程,感觉讲的迷迷糊糊.... 其实感觉他们是对MQTT不够透彻,所以写的文章就是个比着葫芦画瓢的感觉 在我面前这东西就是玩具. ...

  6. hive基础知识五

    Hive 主流文件存储格式对比 1.存储文件的压缩比测试 1.1 测试数据 https://github.com/liufengji/Compression_Format_Data ​ M 1.2 T ...

  7. nodejs内存溢出 FATAL ERROR: CALL_AND_RETRY_0 Allocation failed – process out of memory

    spa项目整体迁移转为ssr后,改动之后部署一切还好,就是突然有一天访问人数太多,node进程很容易就挂了自动重启. 最后经过压力测试,考虑到是堆内存溢出的问题,就报错误:FATAL ERROR: C ...

  8. 2019年底前的web前端面试题初级-web标准应付HR大多面试问题

    作者 | Jeskson来源 | 达达前端小酒馆 问:你知道在css中,html的标签元素分多少中不同的类型吗? 答:大体可分三种:1,块状元素,2,内联元素,3,内联块状元素 块级元素:就是每个块级 ...

  9. 2018-2019-2 网络对抗技术 20165318 Exp7 网络欺诈防范

    2018-2019-2 网络对抗技术 20165318 Exp7 网络欺诈防范 原理与实践说明 实践目标 实践内容概述 基础问题回答 实践过程记录 简单应用SET工具建立冒名网站 ettercap D ...

  10. 2019年上海市大学生网络安全大赛两道misc WriteUp

    2019年全国大学生网络安全邀请赛暨第五届上海市大学生网络安全大赛 做出了两道Misc== 签到 题干 解题过程 题干提示一直注册成功,如果注册失败也许会出现flag. 下载下来是包含010edito ...