最近在调试on2的rmvb硬解码,因为demux代码采用的是ffmpeg的,所以就写了个简单的ffmpeg的应用程序,能够看到每一帧的指定字节数,解码后的YUV图片,很基础吧,就当记录一下
-
/**
-
* decode video by ffmpeg-0.8.14 for rv test
-
*
-
* 2013-04-25
-
* juguofeng
-
*/
-
-
#include <stdlib.h>
-
#include <stdio.h>
-
#include <string.h>
-
-
#include <libavcodec/avcodec.h>
-
#include <libavformat/avformat.h>
-
-
-
FILE *pfout = NULL;
-
char ffrvout[128] = { 0 };
-
-
/* how many yuv pic you want to save */
-
#define FRAME_NUM 50
-
/* enable video demux data save to file */
-
//#define ENABLE_DEMUX_SAVE
-
/* enable yuv pic save to file */
-
#define ENABLE_YUV_SAVE
-
/* enable print each video bytes */
-
#define ENABLE_PRINT_FRAME_BYTES
-
/* how many bytes you want to print */
-
#define PRINT_BYTES 30
-
-
/**
-
* save yuv frame
-
*/
-
void yuv420p_save(AVFrame *pFrame, AVCodecContext *pCodecCtx)
-
{
-
int i = 0;
-
-
int width = pCodecCtx->width, height = pCodecCtx->height;
-
int height_half = height / 2, width_half = width / 2;
-
int y_wrap = pFrame->linesize[0];
-
int u_wrap = pFrame->linesize[1];
-
int v_wrap = pFrame->linesize[2];
-
-
unsigned char *y_buf = pFrame->data[0];
-
unsigned char *u_buf = pFrame->data[1];
-
unsigned char *v_buf = pFrame->data[2];
-
-
//save y
-
for (i = 0; i < height; i++)
-
fwrite(y_buf + i * y_wrap, 1, width, pfout);
-
//save u
-
for (i = 0; i < height_half; i++)
-
fwrite(u_buf + i * u_wrap, 1, width_half, pfout);
-
//save v
-
for (i = 0; i < height_half; i++)
-
fwrite(v_buf + i * v_wrap, 1, width_half, pfout);
-
fflush(pfout);
-
}
-
-
/**
-
* main thread
-
*/
-
int main(int argc, char *argv[])
-
{
-
int i;
-
char szFileName[128] = {0};
-
int decLen = 0;
-
int frame = 0;
-
-
AVCodecContext *pCodecCtx = NULL;
-
AVFrame *pFrame = NULL;
-
AVCodec *pCodec = NULL;
-
AVFormatContext *pFormatCtx = NULL;
-
-
if(argc != 3)
-
{
-
fprintf(stderr, "ERROR:need 3 argument!\n");
-
exit(-1);
-
}
-
-
sprintf(szFileName, "%s", argv[1]);
-
-
#ifdef ENABLE_DEMUX_SAVE
-
FILE* frvdemux = fopen("rvdemuxout.rm","wb+");
-
if (NULL == frvdemux)
-
{
-
fprintf(stderr, "create rvdemuxout file failed\n");
-
exit(1);
-
}
-
#endif
-
-
/* output yuv file name */
-
sprintf(ffrvout, "%s", argv[2]);
-
-
pfout = fopen(ffrvout, "wb+");
-
if (NULL == pfout)
-
{
-
printf("create output file failed\n");
-
exit(1);
-
}
-
printf("==========> Begin test ffmpeg call ffmpeg rv decoder\n");
-
av_register_all();
-
-
/* Open input video file */
-
//printf("before avformat_open_input [%s]\n", szFileName);
-
if(avformat_open_input(&pFormatCtx, szFileName, NULL, NULL)!= 0)
-
{
-
fprintf(stderr, "Couldn't open input file\n");
-
return -1;
-
}
-
//printf("after avformat_open_input\n");
-
-
/* Retrieve stream information */
-
if(av_find_stream_info(pFormatCtx) < 0)
-
{
-
printf("av_find_stream_info ERROR\n");
-
return -1;
-
}
-
//printf("after av_find_stream_info, \n");
-
-
-
/* Find the first video stream */
-
int videoStream = -1;
-
printf("==========> pFormatCtx->nb_streams = %d\n", pFormatCtx->nb_streams);
-
-
for(i = 0; i < pFormatCtx->nb_streams; i++) {
-
if(pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
-
videoStream = i;
-
printf("the first video stream index: videoStream = %d\n",videoStream);
-
break;
-
}
-
}
-
-
if(videoStream == -1)
-
return -1; // Didn't find a video stream
-
-
/* Get a pointer to the codec context for the video stream */
-
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
-
printf("pCodecCtx->codec_id = %d\n", pCodecCtx->codec_id);
-
-
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
-
if(pCodec == NULL) {
-
fprintf(stderr, "can not find decoder!\n");
-
return -1;
-
}
-
-
/* Open codec */
-
if(avcodec_open(pCodecCtx, pCodec)<0)
-
{
-
printf("cannot open software codec\n");
-
return -1; // Could not open codec
-
}
-
printf("==========> Open software codec success\n");
-
-
pFrame = avcodec_alloc_frame();
-
if(pFrame == NULL)
-
{
-
fprintf(stderr, "avcodec_alloc_frame() ERROR\n");
-
return -1;
-
}
-
-
/* flag whether we get a decoded yuv frame */
-
int frameFinished;
-
int packetno = 0;
-
-
AVPacket packet;
-
av_init_packet(&packet);
-
-
while(av_read_frame(pFormatCtx, &packet) >= 0) {
-
//printf("[main]avpkt->slice_count=%d\n", packet.sliceNum);
-
-
/* Is this a packet from the video stream? */
-
if(packet.stream_index == videoStream) {
-
packetno++;
-
#ifdef ENABLE_PRINT_FRAME_BYTES
-
if ( 1 ) {
-
int i;
-
int size = packet.size < PRINT_BYTES ? packet.size : PRINT_BYTES;
-
unsigned char *data = packet.data;
-
printf("===>[%5d] [", packet.size);
-
for (i = 0; i < size; i++)
-
printf("%02x ", data[i]);
-
printf("]\n");
-
}
-
#endif
-
#ifdef ENABLE_DEMUX_SAVE
-
fwrite(packet.data, 1, packet.size, frvdemux);
-
#endif
-
//printf("[the %d packet]packet.size = %d\n", packetno++, packet.size);
-
-
while (packet.size > 0) {
-
decLen = avcodec_decode_video2(pCodecCtx, pFrame, &frameFinished, &packet);
-
//printf("[video_decode_example]after avcodec_decode_video2,decoded=%d\n",decLen);
-
-
if (decLen < 0) {
-
fprintf(stderr, "[video_decode_example]Error while decoding frame %d\n", frame);
-
//exit(1);
-
/* FIXME if decode one frame err, ignore this frame */
-
decLen = packet.size;
-
}
-
-
if (frameFinished) {
-
//printf("got a yuv frame\n");
-
//printf(stderr, "[video_decode_example]saving frame %3d\n", frame);
-
-
/* the picture is allocated by the decoder. no need to free it */
-
if (frame == 1)
-
printf("[video_decode_example]picture->linesize[0]=%d, c->width=%d,c->height=%d\n",
-
pFrame->linesize[0], pCodecCtx->width, pCodecCtx->height);
-
#ifdef ENABLE_YUV_SAVE
-
/* save yuv pic */
-
if (frame < FRAME_NUM) {
-
yuv420p_save(pFrame, pCodecCtx);
-
}
-
#endif
-
/* frame index grow */
-
frame++;
-
}
-
//printf("===========> %d\n", decLen);
-
/* left data in pkt , go on decoding */
-
packet.data += decLen;
-
packet.size -= decLen;
-
}
-
if (frame == FRAME_NUM) {
-
printf("==========> decoded [%d pkt frames] ---> save [%d YUV frames], enough to stop!\n", packetno, FRAME_NUM);
-
break;
-
}
-
}
-
-
/* FIXME no need free in this file */
-
//printf("free packet that was allocated by av_read_frame\n");
-
// Free the packet that was allocated by av_read_frame
-
//av_free_packet(&packet);
-
}
-
-
printf("decoding job down! begin to free\n");
-
/* Free the YUV frame */
-
av_free(pFrame);
-
-
/* Close the codec */
-
avcodec_close(pCodecCtx);
-
-
/* Close the video file */
-
av_close_input_file(pFormatCtx);
-
fclose(pfout);
-
-
printf("==========> END-OK\n");
-
-
return 0;
-
}
再给出Makefile代码
-
# use pkg-config for getting CFLAGS abd LDFLAGS
-
FFMPEG_LIBS=libavdevice libavformat libavfilter libavcodec libswscale libavutil
-
CFLAGS+=$(shell pkg-config --cflags $(FFMPEG_LIBS))
-
LDFLAGS+=$(shell pkg-config --libs $(FFMPEG_LIBS))
-
-
EXAMPLES=ffmpeg-rm-test
-
-
OBJS=$(addsuffix .o,$(EXAMPLES))
-
-
%: %.o
-
$(CC) $< $(LDFLAGS) -o $@
-
-
%.o: %.c
-
$(CC) $< $(CFLAGS) -c -o $@
-
-
.phony: all clean
-
-
all: $(OBJS) $(EXAMPLES)
-
-
clean:
-
rm -rf $(EXAMPLES) $(OBJS)
编译这个程序,需要机子安装ffmpeg的库,最好自己下载一个ffmpeg-0.8分支,或者之后的版本,编译安装到/usr/local/目录下,如果需要的话,环境变量中还需要加上
PKG_CONFIG_PATH和LD_LIBRARY_PATH,不然可能会报找不到ffmpeg的相关库
阅读(5535) | 评论(0) | 转发(0) |