使用 FFmpeg 开发播放器基础
第一节 使用 ffmpeg 解码视频文件
作者:ChinaFFmpeg 孙悟空
使用 ffmpeg 解码多媒体文件之前,首先需要了解一些基本的概念:
容器:多媒体文件中包含视频与音频部分,将音频与视频封装在容器内,封装的形式为容器标准中所规定的格式,除了音频编码数据,视频编码数据,文字编码数据以外,还有一些用来格式化这些数据的字段,组成了容器;
编码器:多媒体文件中包含了视频编码部分与音频编码部分,都为容器所包含;
了解了以上基本概念后,下面看一下解码视频文件的基本步骤:
-
打开视频文件
-
从视频文件中打开视频流
-
从视频流中读取视频信息到视频帧里面
-
如果读取视频真没有完成,就继续从视频流中读取视频信息到视频帧里面
-
对视频帧进行操作,例如解码,绘制到屏幕,保存文件等
-
继续从视频流中读取视频信息到视频帧里面
在执行第2步之前,首先要注意,如果希望使用 ffmpeg 第一步要注册 ffmpeg 的函数,注册完成以后才能够顺利的使用 ffmpeg;
通过这个函数,将ffmpeg中的avformat/avcodec/avfilter等模块全部注册完成了;
接下来就可以打开视频文件;
通过该函数打开视频文件,分析对应的文件的信息,将信息填充进AVFormatContext中,填充完毕以后,可以获得视频流信息;
获得到了视频信息之后,可以知道视频中含多少路视频流,一路视频流用一路视频流的解流方式进行解流,例如音频流,例如视频流,例如字幕流等这里只讲述视频流;当或得到视频流信息后,既可根据对应的视频流的类型进行解码,例如h264,则会根据查找对应的解码器进行获得解码器的信息;
或得到解码器信息后,则可以将解码器打开;
打开解码器以后就可以根据解码信息将对应的frame数据进行读取,本文档来自于孙悟空读取的时候,每一个frame都需要右地方存储,所以,需要申请frame内存空间;
申请完成之后则开始进行了读取视频frame,然后解frame操作;
-
av_read_frame();
-
avcodec_decode_video()
-
av_read_frame();
-
avcodec_decode_video()
av_read_frame会将数据从format中读取出来存储入packet中,然后使用avcodec_decode_video来对packet的data进行解码,然后将对应的解码后的数据存入frame中,frame中的数据可以存储入文件中,也可以直接绘制到屏幕上;
将数据存储入文件中的代码实例如下:
-
#include <libavcodec/avcodec.h>
-
#include <libavformat/avformat.h>
-
#include <libswscale/swscale.h>
-
-
#include <stdio.h>
-
-
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);
-
}
-
-
int main(int argc, char *argv[])
-
{
-
AVFormatContext *pFormatCtx = NULL;
-
int i = 0;
-
int videoStream = 0;
-
AVCodecContext *pCodecCtx = NULL;
-
AVCodec *pCodec = NULL;
-
AVFrame *pFrame = NULL;
-
AVFrame *pFrameRGB = NULL;
-
AVPacket packet;
-
int frameFinished;
-
int numBytes;
-
uint8_t *buffer = NULL;
-
-
AVDictionary *optionsDict = 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();
-
// Open video file
-
if(avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
-
return -1; // Couldn't open file
-
// 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
OSX下编译方法如下:
-
gcc -Wall -ggdb test.c -I/usr/include/SDL/ -c -o test.o
-
gcc -Wall -ggdb test.o -L/usr/local/lib -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavutil -framework QTKit -framework Foundation -framework QuartzCore -framework CoreVideo -framework Foundation -framework AVFoundation -framework CoreMedia -framework CoreFoundation -framework VideoDecodeAcceleration -framework QuartzCore -liconv -L/usr//lib -lSDLmain -lSDL -Wl,-framework,Cocoa -lm -lbz2 -lz -pthread -o test
Linux下编译方法如下:
-
gcc -Wall -ggdb test.c -I/usr/include/SDL/ -c -o test.o
-
gcc -Wall -ggdb test.o -o test -L/usr/local/lib -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavuti -lm -lbz2 -lz -pthread
-
gcc -Wall -ggdb test.c -I/usr/include/SDL/ -c -o test.o
-
gcc -Wall -ggdb test.o -o test -L/usr/local/lib -lavdevice -lavfilter -lavformat -lavcodec -lswresample -lswscale -lavuti -lm -lbz2 -lz -pthread
-
ffmpeg version N-63027-g9e58677 Copyright (c) 2000-2014 the FFmpeg developers
-
built on Jun 1 2014 17:05:37 with Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)
-
configuration: --prefix=/usr/local/
-
libavutil 52. 81.100 / 52. 81.100
-
libavcodec 55. 60.103 / 55. 60.103
-
libavformat 55. 37.102 / 55. 37.102
-
libavdevice 55. 13.101 / 55. 13.101
-
libavfilter 4. 5.100 / 4. 5.100
-
libswscale 2. 6.100 / 2. 6.100
-
libswresample 0. 18.100 / 0. 18.100
阅读(15044) | 评论(1) | 转发(5) |