ffmpeg学习(一)

由于之前偶尔接触ffmpeg,但都没有深入的研究ffmpeg,所以打算一步步学习ffmpeg,写出我的学习过程,也希望各位高手能给于指点,给我提供更加便捷的学习之路。有一起学习的朋友,希望能多多交流。

1. ffmpeg编译(Ubuntu或者centos平台)

这里不多说,百度到处都是;

2. ffmpeg入门很难,各种资料很多,但一开始就各种专业函数其实很难理解,我在网上参考参考别人的代码做了一个读取264文件的例子。(frame没用到,我没删掉。)

//
//g++ read264.cpp  -lavcodec

#include <stdio.h>
#include <string.h>
#include "Read.h"
#include <iostream>
using namespace std;

#define BUFFLEN 1024
#define in_buffer_size  4096

extern "C"
{
#include "libavcodec/avcodec.h"

AVCodec *pCodec;
AVCodecContext *pCodecCtx= NULL;
AVCodecParserContext *pCodecParserCtx=NULL;
AVFrame   *pFrame;

FILE *fp_in;
uint8_t in_buffer[in_buffer_size + FF_INPUT_BUFFER_PADDING_SIZE];
int cur_size;

uint8_t *cur_ptr;
AVPacket packet;

enum AVCodecID codec_id=AV_CODEC_ID_H264;

int first_time = 1;
struct SwsContext *img_convert_ctx;

int Read264(char* filepath_in )
{
    int ret;
    avcodec_register_all();
    pCodec = avcodec_find_decoder(codec_id);
    if (!pCodec) 
    {   
        fprintf(stderr, "Codec not found\n");
        exit(1);               
    }
    pCodecCtx = avcodec_alloc_context3(pCodec);
    if (!pCodecCtx)
    {
        printf("Could not allocate video codec context\n");
        return -1;
    }
    pCodecParserCtx=av_parser_init(codec_id);
    if (!pCodecParserCtx){
        printf("Could not allocate video parser context\n");
        return -1;
    }
    
    if(pCodec->capabilities&CODEC_CAP_TRUNCATED)
        pCodecCtx->flags|= CODEC_FLAG_TRUNCATED; /* we do not send complete frames */
    if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) 
    {
        printf("Could not open codec\n");
        return -1;              
    }
    //Input File
    fp_in = fopen(filepath_in, "rb");
    if (!fp_in)     
    {
        printf("Could not open input stream\n");
        return -1;
    }
    
    pFrame = av_frame_alloc();
    av_init_packet(&packet); 

    int frameNum = 0;
    while(1)
    {
        cur_size = fread(in_buffer, 1, in_buffer_size, fp_in);
        if (cur_size == 0)
            break;
        cur_ptr = in_buffer;
        while (cur_size>0)
        {
            int len = <strong>av_parser_parse2</strong>(pCodecParserCtx, pCodecCtx, &packet.data, &packet.size, cur_ptr , cur_size , AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);
            cur_ptr += len;
            cur_size -= len;
            if(packet.size==0)
                continue;

            //for one frame
            printf("frame: %d ", frameNum++);
            //Some Info from AVCodecParserContext
            printf("Packet Size:%6d\t",packet.size);
            switch(pCodecParserCtx->pict_type)
            {
                case AV_PICTURE_TYPE_I: printf("Type: I\t");break;
                case AV_PICTURE_TYPE_P: printf("Type: P\t");break;
                case AV_PICTURE_TYPE_B: printf("Type: B\t");break;
                default: printf("Type: Other\t");break;
            }
            cout<<endl;
        }    
    }
    fclose(fp_in);
    av_parser_close(pCodecParserCtx);
    av_frame_free(&pFrame);
    avcodec_close(pCodecCtx);                                                                                                                                           
    av_free(pCodecCtx);
    return 0;
}
}
int main(int argc, char** argv)
{
    int ret;
    char filepath_in[] = "test.264";
    ret = Read264(filepath_in);
    if(ret < 0)
    {
        printf("Read error!");
        return -1;
    }
    return 0;
}

这个例子用于读取264码流文件,并解析出帧类型I/P/B,计算帧数。

解析函数是

int 	av_parser_parse2 (AVCodecParserContext *s, AVCodecContext *avctx, uint8_t **poutbuf, int *poutbuf_size, const uint8_t *buf, int buf_size, int64_t pts, int64_t dts, int64_t pos)

程序调用时为:

int len = av_parser_parse2(pCodecParserCtx, pCodecCtx, &packet.data, &packet.size, cur_ptr , cur_size , AV_NOPTS_VALUE, AV_NOPTS_VALUE, AV_NOPTS_VALUE);


如果要查看函数的话,我建议去官网上找到avcodec.h文件查看,因为浏览网页的方式很方便,一目了然

http://ffmpeg.org/doxygen/2.6/libavcodec_2avcodec_8h.html

找到后也不需要点进去看函数内容,只需要看参数就可以了。如果要仔细研究,雷神博客:

http://blog.csdn.net/leixiaohua1020/article/details/12679719

(1) pCodecParserCtx

//定义

AVCodecParserContext *pCodecParserCtx=NULL;
//初始化
pCodecParserCtx=av_parser_init(codec_id);
    if (!pCodecParserCtx){
        printf("Could not allocate video parser context\n");
        return -1;
    }
</pre>
(2)初始化时的参数
<pre name="code" class="html">codec_id
//定义
enum AVCodecID codec_id=AV_CODEC_ID_H264;

 如果是其他格式的,可查看AVCodecID枚举类型,找到对应的类型。 

(3) 参数2

<pre name="code" class="html">pCodecCtx
 //定义: 

AVCodecContext *pCodecCtx= NULL;

//初始化

    pCodecCtx = avcodec_alloc_context3(pCodec);    if (!pCodecCtx)    {        printf("Could not allocate video codec context\n");        return -1;    }

初始化的参数pCodec:(编解码器)

 pCodec = avcodec_find_decoder(codec_id);
    if (!pCodec) 
    {   
        fprintf(stderr, "Codec not found\n");
        exit(1);               
    }
(4) 参数3和:4:&packet.data;  &packet.size  输出buffer

AVPacket packet;
//初始化
av_init_packet(&packet); 
(5) 参数5和6: cur_ptr(当前指针)、cur_size(内容长度)

int cur_size;
uint8_t *cur_ptr;
cur_ptr = in_buffer;
inbuffer:
        cur_size = fread(in_buffer, 1, in_buffer_size, fp_in);

然后调用 av_parser_parse2函数,完成码流解析。

解析后的帧类型在第一个参数中:

pCodecParserCtx->pict_type

如此,该程序顺利完成。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值