FFmpeg SDK开发模型之中的一个:解码器
Posted ldxsuanfa
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FFmpeg SDK开发模型之中的一个:解码器相关的知识,希望对你有一定的参考价值。
简单介绍
一、源代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif
#include "libavcodec/avcodec.h"
#define INBUF_SIZE 4096
void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
{
? FILE *f;
? int i;
? f=fopen(filename,"w");
? fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
? for(i=0;i<ysize;i++)
? fwrite(buf + i * wrap,1,xsize,f);
? fclose(f);
}
/*
?* Video decoding
?*/
void video_decode_example(const char *outfilename, const char *filename)
{
? AVCodec *codec;
? AVCodecContext *c= NULL;
? int frame, size, got_picture, len;
? FILE *f;
? AVFrame *picture;
? uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr;
? char buf[1024];
? uint8_t *pkt_ptr, pkt_len;
? /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
? memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
? printf("Video decoding\n");
? /* find the mpeg1 video decoder */
? //codec = avcodec_find_decoder(CODEC_ID_H264);
? codec = avcodec_find_decoder(CODEC_ID_MPEG2VIDEO);
? if (!codec) {
? ? fprintf(stderr, "codec not found\n");
? ? exit(1);
? }
? c= avcodec_alloc_context();
? picture= avcodec_alloc_frame();
? if(codec->capabilities&CODEC_CAP_TRUNCATED)
? c->flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */
? /* for some codecs, such as msmpeg4 and mpeg4, width and height
? ? ?MUST be initialized there because these info are not available
? ? ?in the bitstream */
? /* open it */
? if (avcodec_open(c, codec) < 0) {
? ? fprintf(stderr, "could not open codec\n");
? ? exit(1);
? }
? /* the codec gives us the frame size, in samples */
? f = fopen(filename, "rb");
? if (!f) {
? ? fprintf(stderr, "could not open %s\n", filename);
? ? exit(1);
? }
? frame = 0;
? for(;;) {
? ? AVPacket pkt;
? ? if (av_read_frame(c, &pkt) < 0) {
? ? ? continue;
? ? }
? ? // ? ? ? ?size = fread(inbuf, 1, INBUF_SIZE, f);
? ? // ? ? ? ?if (size == 0)
? ? // ? ? ? ? ? ?break;
? ? /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
? ? ? ?and this is the only method to use them because you cannot
? ? ? ?know the compressed data size before analysing it.
? ? ? ?BUT some other codecs (msmpeg4, mpeg4) are inherently frame
? ? ? ?based, so you must call them with all the data for one
? ? ? ?frame exactly. You must also initialize ‘width‘ and
? ? ? ?‘height‘ before initializing them. */
? ? /* NOTE2: some codecs allow the raw parameters (frame size,
? ? ? ?sample rate) to be changed at any frame. We handle this, so
? ? ? ?you should also take care of it */
? ? /* here, we use a stream based decoder (mpeg1video), so we
? ? ? ?feed decoder and see if it could decode a frame */
? ? pkt_len = pkt.size;
? ? pkt_ptr = pkt.data;
? ? // ?inbuf_ptr = inbuf;
? ? while (pkt_len > 0) {
? ? ? len = avcodec_decode_video2(c, picture, &got_picture,
? ? ? ? ? ? &pkt);
? ? ? if (len < 0) {
? ? ? ? fprintf(stderr, "Error while decoding frame %d\n", frame);
? ? ? ? exit(1);
? ? ? }
? ? ? if (got_picture) {
? ? ? ? printf("saving frame %3d\n", frame);
? ? ? ? fflush(stdout);
? ? ? ? /* the picture is allocated by the decoder. no need to
? ? ? ? ? ?free it */
? ? ? ? snprintf(buf, sizeof(buf), outfilename, frame);
? ? ? ? pgm_save(picture->data[0], picture->linesize[0],
? ? ? ? ? ? ? c->width, c->height, buf);
? ? ? ? frame++;
? ? ? }
? ? ? size -= len;
? ? ? inbuf_ptr += len;
? ? }
? ? av_free_packet(&pkt);
? }
? /* some codecs, such as MPEG, transmit the I and P frame with a
? ? ?latency of one frame. You must do the following to have a
? ? ?chance to get the last frame of the video */
? len = avcodec_decode_video2(c, picture, &got_picture,
? ? ? ? NULL);
? if (got_picture) {
? ? printf("saving last frame %3d\n", frame);
? ? fflush(stdout);
? ? /* the picture is allocated by the decoder. no need to
? ? ? ?free it */
? ? snprintf(buf, sizeof(buf), outfilename, frame);
? ? pgm_save(picture->data[0], picture->linesize[0],
? ? ? ? ? c->width, c->height, buf);
? ? frame++;
? }
? fclose(f);
? avcodec_close(c);
? av_free(c);
? av_free(picture);
? printf("\n");
}
int main(int argc, char **argv)
{
? const char *filename;
? /* must be called before using avcodec lib */
? avcodec_init();
? /* register all the codecs (you can also register only the codec
? ? ?you wish to have smaller code */
? avcodec_register_all();
? if (argc <= 1) {
? ? // ? ? ? ?audio_encode_example("/tmp/test.mp2");
? ? // ? ? ? ?audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
? ? video_encode_example("/tmp/test.mpg");
? ? filename = "/tmp/test.mpg";
? } else {
? ? filename = argv[1];
? }
? // ? ?audio_decode_example("/tmp/test.sw", filename);
? video_decode_example("/tmp/test%d.pgm", filename);
? return 0;
}
二、代码分析
01 ?avcodec_init(), 初始化libavcodec
02 ?avcodec_register_all(), 注冊全部编解码器和格式
03 ?codec = avcodec_find_decoder(CODEC_ID_MPEG2VIDEO), 查找mpeg2 video解码器
04 ?c ? ? = avcodec_alloc_context(), 分配AVCodecContext空间并初始化
05 ?picture = avcodec_alloc_frame(), 分配AVFrame的空间
06 ?avcodec_open(c, codec), ?使用codec来初始化c
07 ?FOR循环 {
? ? ? 07.1 av_read_frame(c, &pkt), 从输入文件里读取一个包
? ? ? 07.2 pkt_len = pkt.size;
? ? ? ? ? ?pkt_ptr = pkt.data;
? ? ? 07.3 while(pkt_len > 0) {
? ? ? ? ? ? ?07.3.1 avcodec_decode_video2(c, picture, &got_picture, &pkt), 解码当前包
? ? ? ? ? ? ?07.3.2 if (got_picture) {
? ? ? ? ? ? ? ? ? ? ? ?pgm_save(picture->data[0], ...), 对解码后的YUV数据进行处理;
? ? ? ? ? ? ? ? ? ? ? ?frame++;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ?07.3.3 size -= len;
? ? ? ? ? ?}
? ? ? 07.4 av_free_packet(&pkt), 释放当前包
? ? }
08 ?len = avcodec_decode_video2(c, picture, &got_picture, NULL); 解码最后的帧;
09 ?if (got_picture) { ...}, 处理最后帧的YUV数据
10 ?avcodec_close(c);
11 ?av_free(c)
12 ?av_free(picture);
本例解说了怎样使用ffmpeg SDK解码媒体文件;
參考源代码是ffmpeg 自带的apiexample.c
一、源代码
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#ifdef HAVE_AV_CONFIG_H
#undef HAVE_AV_CONFIG_H
#endif
#include "libavcodec/avcodec.h"
#define INBUF_SIZE 4096
void pgm_save(unsigned char *buf,int wrap, int xsize,int ysize,char *filename)
{
? FILE *f;
? int i;
? f=fopen(filename,"w");
? fprintf(f,"P5\n%d %d\n%d\n",xsize,ysize,255);
? for(i=0;i<ysize;i++)
? fwrite(buf + i * wrap,1,xsize,f);
? fclose(f);
}
/*
?* Video decoding
?*/
void video_decode_example(const char *outfilename, const char *filename)
{
? AVCodec *codec;
? AVCodecContext *c= NULL;
? int frame, size, got_picture, len;
? FILE *f;
? AVFrame *picture;
? uint8_t inbuf[INBUF_SIZE + FF_INPUT_BUFFER_PADDING_SIZE], *inbuf_ptr;
? char buf[1024];
? uint8_t *pkt_ptr, pkt_len;
? /* set end of buffer to 0 (this ensures that no overreading happens for damaged mpeg streams) */
? memset(inbuf + INBUF_SIZE, 0, FF_INPUT_BUFFER_PADDING_SIZE);
? printf("Video decoding\n");
? /* find the mpeg1 video decoder */
? //codec = avcodec_find_decoder(CODEC_ID_H264);
? codec = avcodec_find_decoder(CODEC_ID_MPEG2VIDEO);
? if (!codec) {
? ? fprintf(stderr, "codec not found\n");
? ? exit(1);
? }
? c= avcodec_alloc_context();
? picture= avcodec_alloc_frame();
? if(codec->capabilities&CODEC_CAP_TRUNCATED)
? c->flags|= CODEC_FLAG_TRUNCATED; /* we dont send complete frames */
? /* for some codecs, such as msmpeg4 and mpeg4, width and height
? ? ?MUST be initialized there because these info are not available
? ? ?in the bitstream */
? /* open it */
? if (avcodec_open(c, codec) < 0) {
? ? fprintf(stderr, "could not open codec\n");
? ? exit(1);
? }
? /* the codec gives us the frame size, in samples */
? f = fopen(filename, "rb");
? if (!f) {
? ? fprintf(stderr, "could not open %s\n", filename);
? ? exit(1);
? }
? frame = 0;
? for(;;) {
? ? AVPacket pkt;
? ? if (av_read_frame(c, &pkt) < 0) {
? ? ? continue;
? ? }
? ? // ? ? ? ?size = fread(inbuf, 1, INBUF_SIZE, f);
? ? // ? ? ? ?if (size == 0)
? ? // ? ? ? ? ? ?break;
? ? /* NOTE1: some codecs are stream based (mpegvideo, mpegaudio)
? ? ? ?and this is the only method to use them because you cannot
? ? ? ?know the compressed data size before analysing it.
? ? ? ?BUT some other codecs (msmpeg4, mpeg4) are inherently frame
? ? ? ?based, so you must call them with all the data for one
? ? ? ?frame exactly. You must also initialize ‘width‘ and
? ? ? ?‘height‘ before initializing them. */
? ? /* NOTE2: some codecs allow the raw parameters (frame size,
? ? ? ?sample rate) to be changed at any frame. We handle this, so
? ? ? ?you should also take care of it */
? ? /* here, we use a stream based decoder (mpeg1video), so we
? ? ? ?feed decoder and see if it could decode a frame */
? ? pkt_len = pkt.size;
? ? pkt_ptr = pkt.data;
? ? // ?inbuf_ptr = inbuf;
? ? while (pkt_len > 0) {
? ? ? len = avcodec_decode_video2(c, picture, &got_picture,
? ? ? ? ? ? &pkt);
? ? ? if (len < 0) {
? ? ? ? fprintf(stderr, "Error while decoding frame %d\n", frame);
? ? ? ? exit(1);
? ? ? }
? ? ? if (got_picture) {
? ? ? ? printf("saving frame %3d\n", frame);
? ? ? ? fflush(stdout);
? ? ? ? /* the picture is allocated by the decoder. no need to
? ? ? ? ? ?free it */
? ? ? ? snprintf(buf, sizeof(buf), outfilename, frame);
? ? ? ? pgm_save(picture->data[0], picture->linesize[0],
? ? ? ? ? ? ? c->width, c->height, buf);
? ? ? ? frame++;
? ? ? }
? ? ? size -= len;
? ? ? inbuf_ptr += len;
? ? }
? ? av_free_packet(&pkt);
? }
? /* some codecs, such as MPEG, transmit the I and P frame with a
? ? ?latency of one frame. You must do the following to have a
? ? ?chance to get the last frame of the video */
? len = avcodec_decode_video2(c, picture, &got_picture,
? ? ? ? NULL);
? if (got_picture) {
? ? printf("saving last frame %3d\n", frame);
? ? fflush(stdout);
? ? /* the picture is allocated by the decoder. no need to
? ? ? ?free it */
? ? snprintf(buf, sizeof(buf), outfilename, frame);
? ? pgm_save(picture->data[0], picture->linesize[0],
? ? ? ? ? c->width, c->height, buf);
? ? frame++;
? }
? fclose(f);
? avcodec_close(c);
? av_free(c);
? av_free(picture);
? printf("\n");
}
int main(int argc, char **argv)
{
? const char *filename;
? /* must be called before using avcodec lib */
? avcodec_init();
? /* register all the codecs (you can also register only the codec
? ? ?you wish to have smaller code */
? avcodec_register_all();
? if (argc <= 1) {
? ? // ? ? ? ?audio_encode_example("/tmp/test.mp2");
? ? // ? ? ? ?audio_decode_example("/tmp/test.sw", "/tmp/test.mp2");
? ? video_encode_example("/tmp/test.mpg");
? ? filename = "/tmp/test.mpg";
? } else {
? ? filename = argv[1];
? }
? // ? ?audio_decode_example("/tmp/test.sw", filename);
? video_decode_example("/tmp/test%d.pgm", filename);
? return 0;
}
二、代码分析
01 ?avcodec_init(), 初始化libavcodec
02 ?avcodec_register_all(), 注冊全部编解码器和格式
03 ?codec = avcodec_find_decoder(CODEC_ID_MPEG2VIDEO), 查找mpeg2 video解码器
04 ?c ? ? = avcodec_alloc_context(), 分配AVCodecContext空间并初始化
05 ?picture = avcodec_alloc_frame(), 分配AVFrame的空间
06 ?avcodec_open(c, codec), ?使用codec来初始化c
07 ?FOR循环 {
? ? ? 07.1 av_read_frame(c, &pkt), 从输入文件里读取一个包
? ? ? 07.2 pkt_len = pkt.size;
? ? ? ? ? ?pkt_ptr = pkt.data;
? ? ? 07.3 while(pkt_len > 0) {
? ? ? ? ? ? ?07.3.1 avcodec_decode_video2(c, picture, &got_picture, &pkt), 解码当前包
? ? ? ? ? ? ?07.3.2 if (got_picture) {
? ? ? ? ? ? ? ? ? ? ? ?pgm_save(picture->data[0], ...), 对解码后的YUV数据进行处理;
? ? ? ? ? ? ? ? ? ? ? ?frame++;
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ?07.3.3 size -= len;
? ? ? ? ? ?}
? ? ? 07.4 av_free_packet(&pkt), 释放当前包
? ? }
08 ?len = avcodec_decode_video2(c, picture, &got_picture, NULL); 解码最后的帧;
09 ?if (got_picture) { ...}, 处理最后帧的YUV数据
10 ?avcodec_close(c);
11 ?av_free(c)
12 ?av_free(picture);