ffmpeg 学习: 004-参考文档进行的开发
背景
在学习ffmpeg时,由于文档老旧以及ffmpeg新旧版本对于一些api的改动,导致学习受阻。
本来可以直接下载老的库,使用老的源码进行学习,但本人觉得,一味地守旧并不是一种好的方法。
ffmpeg 文档:
思路
由于对于FFmpeg的了解还比较皮毛,所以我们使用一些旧的例程,将提示过时的方法改为新的方法。
首先,我们查看一份过时的例程
下面的代码基于 ffmpeg v4.0 编译,为了保证编译通过,已经事先做了小部分的更改。
// ffmpeg v4.0
#include <stdio.h>
#define __STDC_CONSTANT_MACROS
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavfilter/avfilter.h>
#include <libswscale/swscale.h>
//#include <libavutil/imgutils.h>
#ifdef __cplusplus
};
#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;
fprintf(pFile, "p6 \n %d %d\n", width, height);
for (y=0; y< height;y++)
{
fwrite(pFrame->data[0]+ y*pFrame->linesize[0], 1, width*3, pFile);
}
// Close file
fclose(pFile);
}
int main(int argc, char *argv[])
{
AVFormatContext *pFormatCtx;
int i, videoStream;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame;
AVFrame *pFrameRGB;
AVPacket packet;
int frameFinished;
int numBytes;
uint8_t *buffer;
if (argc <2 )
{
printf("Please provide a movie file\n");
return -1;
}
av_register_all();
avformat_network_init();
pFormatCtx = avformat_alloc_context();
// Open the media file and read the header
if (avformat_open_input(&pFormatCtx, argv[1], NULL,NULL)!=0)
{
printf("Couldn't open file\n");
return -1;
}
// retrieve stream information
if(avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1;
// dump information about file into stand error
av_dump_format(pFormatCtx, -1, argv[1], 0);
// Find the first video stream
videoStream = -1;
for(i =0; i< pFormatCtx->nb_streams; i++)
{
if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
printf("First stream is [%d]\n", videoStream);
break;
}
}
if (videoStream == -1)
return -1;
// Get a pointer to the codec context for the video stream
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if(pCodec == NULL)
{
fprintf(stderr, "unsupported codec\n");
return -1;
}
// Open codec
if(avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
return -1;
// allocate video frame
pFrame = av_frame_alloc();
if (NULL == pFrame) return -1;
// 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);
printf("avpicture isze is %d\n", numBytes);
buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *)pFrameRGB, buffer, AV_PIX_FMT_RGB24, pCodecCtx->width, pCodecCtx->height);
i = 0;
while(av_read_frame(pFormatCtx, &packet) >= 0)
{
if(packet.stream_index ==videoStream)
{
avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
if(frameFinished)
{
struct SwsContext * img_convert_ctx = NULL;
img_convert_ctx = sws_getCachedContext(img_convert_ctx, pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_RGB24, SWS_BICUBIC,
NULL, NULL, NULL);
if (!img_convert_ctx)
{
fprintf(stderr, "Cannot initalize sws conversion context\n");
exit (-1);
}
sws_scale(img_convert_ctx, pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameRGB->data, pFrameRGB->linesize);
if(i ++ < 50)
SaveFrame(pFrameRGB, pCodecCtx->width, pCodecCtx->height, i);
}
}
av_packet_unref(&packet);
}
// Free the RGB image
av_free(buffer);
av_free(pFrameRGB);
av_free(pFrame);
avcodec_close(pCodecCtx);
//av_close_input_file(pFormatCtx);
avformat_close_input(&pFormatCtx);
return 0;
}
编译,除了一堆警告以外,没有什么错误。
开始修改
先将每一个警告消除。
-
变量类型的不匹配
for(i =0; i< pFormatCtx->nb_streams; i++)
出现问题
查阅有关的数据结构发现,是变量类型不匹配,将i改成 uint。 -
成员改名
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
提示codec
过气
同样,查阅以后,将codec
修改为codecpar
-
处理方式不同
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
之前的版本
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
之后的版本
pCodecCtx = avcodec_alloc_context3(NULL);
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
if (pCodecCtx == NULL)
{
// printf("Could not allocate AVCodecContext\n");
return -1;
}
if (pFormatCtx->streams[i]/*视音频流*/->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
// 处理音频
}
avcodec_parameters_to_context(pCodecCtx, pFormatCtx->streams[videoStream]->codecpar);
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
- 过气函数
avpicture_get_size
官方文档已经在 libavcodec/avcodec.h 说明:
/**
* @deprecated use av_image_get_buffer_size() instead.
*/
attribute_deprecated int avpicture_get_size(enum AVPixelFormat pix_fmt, int width, int height);
由于没有在文档中很快找到 av_image_get_buffer_size
,于是我在 头文件目录下搜索grep -nR av_image_get_buffer_size
,找到是 libavutil这里的函数
libavcodec/avcodec.h:5650: * @deprecated use av_image_get_buffer_size() instead.
libavutil/imgutils.h:181:int av_image_get_buffer_size(enum AVPixelFormat pix_fmt, int width, int height, int align);
libavutil/imgutils.h:186: * av_image_get_buffer_size() can be used to compute the required size
如果说我的文章对你有用,只不过是我站在巨人的肩膀上再继续努力罢了。
若在页首无特别声明,本篇文章由 Schips 经过整理后发布。
博客地址:https://www.cnblogs.com/schips/
若在页首无特别声明,本篇文章由 Schips 经过整理后发布。
博客地址:https://www.cnblogs.com/schips/