来源: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. Kinect一代学习(一):开发环境搭建

    https://blog.csdn.net/hongbin_xu/article/details/80722749 我用的是kinect一代(Xbox 360)的所以选择了v1.x的SDK,如果是ki ...

  2. Pandas | 19 合并/连接

    Pandas具有功能全面的高性能内存中连接操作,与SQL等关系数据库非常相似.Pandas提供了一个单独的merge()函数,作为DataFrame对象之间所有标准数据库连接操作的入口 - pd.me ...

  3. MongoDB的安装与简单使用

    一.安装MongoDB的步骤 注:本教程全部统一采用hadoop用户名登录Linux系统,用户名:hadoop 密码:hadoop ​ 首先,在Linux系统中打开一个终端,执行如下命令导入公共秘钥到 ...

  4. ESA2GJK1DH1K升级篇: 远程升级准备工作: 使用TCP客户端连接Web服务器实现http下载数据

    一,根目录建一个文件 二,使用浏览器访问 http://47.92.31.46:80/1.txt     或者  http://47.92.31.46/1.txt 三,使用TCP客户端访问文件内容 3 ...

  5. VueCli3如何传递scss全局变量

    当我们尝试在一个scss文件中定义全局变量然后在.vue文件中使用的时候 哦豁,找不到变量,意料之外 我发现犯了一个错误,没导入,@import 'path/to/file.scss',不过这样的话, ...

  6. 实例解读什么是Redis缓存穿透、缓存雪崩和缓存击穿

    from:https://baijiahao.baidu.com/s?id=1619572269435584821&wfr=spider&for=pc Redis缓存的使用,极大的提升 ...

  7. [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设

    [HeadFrist-HTMLCSS学习笔记]第三章构建模块:Web页面建设 敲黑板!! <q>元素添加短引用,<blockquote>添加长引用 在段落里添加引用就使用< ...

  8. [解决方案]IIS常见问题集锦

    内容 地址 更新时间 IIS7如何实现访问HTTP跳转到HTTPS访问 https://www.cnblogs.com/xiefengdaxia123/p/8542737.html 2019-10-1 ...

  9. 使用rxjs以及javascript解决前端的防抖和节流

    JavaScript实现方式: 防抖 触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间:思路:每次触发事件时都取消之前的延时调用方法: 举个例子:做一个自动查 ...

  10. linux系统命令别名,打造属于自己的个性linux系统

    linux操作系统,个性化快捷命令,让你的系统更懂你,让你的操作更快捷. 在你使用linux操作系统的时候,有时候输入命令过长的话会显得很麻烦,这个时候,linux操作系统支持的命令别名很大程度上解决 ...