FFmpeg学习教程

364人阅读 评论(0) 收藏 举报
分类:

一、FFmpeg库介绍

FFmpeg一共包含8个库:
1、avcodec:编解码(最重要的库)。
2、avformat:封装格式处理。
3、avfilter:滤镜特效处理。
4、avdevice:各种设备的输入输出。
5、avutil:工具库(大部分库都需要这个库的支持)。
6、postproc:后加工。
7、swresample:音频采样数据格式转换。
8、swscale:视频像素数据格式转换。
FFmpeg解码函数简介:
1、av_register_all();//注册所有文件格式和编解码库
2、avformat_network_init();//打开网络视频流
3、av_open_input_file();//读取文件头部把信息保存到AVFormatContext结构体
4、av_find_stream_info();//为pFormatCtx->streams填充上正确的信息
5、CODEC_TYPE_VIDEO;//通过判断得到视频流类型
6、avcodec_find_decoder();//查找解码器
7、avcodec_open();//打开编解码器
8、avcodec_alloc_frame();//分配空间保存帧数据
9、av_read_frame();//不断从流中提取帧数据
10、avcodec_decode_video();//解码视频流
11、avcodec_close();//关闭解码器
12、avformat_close_input_file();//关闭输入文件

FFmpeg解码的流程图如下所示:


二、FFmpeg数据结构详解:

1、AVFormatContext

   描述媒体文件或媒体流构成和基本信息(包含码流参数较多,位于:avformat.h),封装格式上下文结构体,也是统领全局的结构体,保存了视频文件封装格式相关信息
主要变量:
struct AVInputFormat *iformat:输入数据的封装格式
AVIOContext *pb:输入数据缓存
unsigned int nb_streams:音视频流个数(输入视频的AVStream 个数)
AVStream **streams:音视频流(输入视频的AVStream []数组)
char filename[1024]:文件名
int64_t duration:时长(单位:us)(输入视频的时长(以微秒为单位))
int bit_rate:比特率(输入视频的码率)
AVDictionary *metadata:元数据

2、AVInputFormat

   每种封装格式(例如FLV, MKV, MP4, AVI)对应一个该结构体。
long_name:封装格式的长名称
extensions:封装格式的扩展名
id:封装格式ID
一些封装格式处理的接口函数

3、AVCodecContext:

   描述编解码器上下文的数据结构,包含编解码器需要的参数信息(位于:avcodec.h),编码器上下文结构体,保存了视频(音频)编解码相关信息
说明:
codec:编解码器的AVCodec
width, height:图像的宽高(只针对视频)
pix_fmt:像素格式(只针对视频)
sample_rate:采样率(只针对音频)
channels:声道数(只针对音频)
sample_fmt:采样格式(只针对音频)

4、AVStream:

   描述一个媒体流(存储视频/音频流信息的结构体,位于:avformat.h),视频文件中每个视频(音频)流对应一个该结构体
主要变量:
AVCodecContext *codec:视频/音频流的AVCodecContext
AVRational time_base:时间基准,真正的时间 =PTS*time_base
int64_t duration:该视频/音频流时间长度
AVDictionary *metadata:元数据信息
AVRational avg_frame_rate:帧率
AVPacket attached_pic:附加图片

5、AVCodec

每种视频(音频)编解码器(例如H.264解码器)对应一个该结构体。

name:编解码器名称
long_name:编解码器长名称
type:编解码器类型
id:编解码器ID
一些编解码的接口函数

6、AVPacket:

  存储一帧压缩编码数据。

uint8_t *data:压缩编码数据,一个AVPacket的data通常对应一个NAL。
int   size:data的大小
int64_t pts:显示时间戳
int64_t dts:解码时间戳
int   stream_index:标识该AVPacket所属的视频/音频流。

7、AVFrame

   存储一帧解码后像素(采样)数据。
data:解码后的图像像素数据(音频采样数据)。
linesize:对视频来说是图像中一行像素的大小;对音频来说是整个音频帧的大小。
width, height:图像的宽高(只针对视频)。
key_frame:是否为关键帧(只针对视频) 。
pict_type:帧类型(只针对视频) 。例如I,P,B。

三、API

1、int avformat_open_input(AVFormatContext **ic_ptr,const char *filename,AVInputFormat *fmt,AVDictionary **options);
作用:打开文件或URL,并使基于字节流的底层输入模块得到初始化;解析多媒体文件或多媒体流的头信息,创建AVFormatContext结构并填充其中的关键字段,依次为各个原始流建立AVStream结构。
参数:
ic_ptr:用于返回avformat_open_input内部构造的一个AVFormatContext结构体。
filename:指定文件名。
fmt:用于显式指定输入文件的格式,如果设为空则自动判断其输入格式。
options:传入的附加参数。
 说明:这个函数通过解析多媒体文件或流的头信息及其他辅助数据,能够获取足够多的关于文件、流和编解码器的信息,但任何一种多媒体格式提供的信息都是有限的,而且不同的多媒体软件制作对头信息的设置各有不同,另外这些软件在产生多媒体内容时难免引入错误,这种情况下并不能保证获取到所有需要的信息,这是就要考虑另一个函数:avformat_find_stream_info。


2、int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options);
作用:用于获取必要的编解码器参数。需要得到各媒体流对应编解码器的类型和id,这是两个定义在avutils.h和avcodec.h中的枚举:
enum AVMediaType {
     AVMEDIA_TYPE_UNKNOWN = -1,
     AVMEDIA_TYPE_VIDEO,
     AVMEDIA_TYPE_AUDIO,
     AVMEDIA_TYPE_DATA,
     AVMEDIA_TYPE_SUBTITLE,
     AVMEDIA_TYPE_ATTACHMENT,
     AVMEDIA_TYPE_NB
};
enum CodecID {
     CODEC_ID_NONE,
     CODEC_ID_MPEG1VIDEO,
     CODEC_ID_MPEG2VIDEO,
     CODEC_ID_MPEG2VIDEO_XVMC,
     CODEC_ID_H261,
     CODEC_ID_H263,
CODEC_ID_H264,
     ...
};
若媒体格式的数据流具有完整头信息,可以通过avformat_open_input得到编解码器的类型和id;否则,需要通过avformat_find_stream_info函数获取。此外,对于音频编解码器,时间基准、采样率、声道数、位宽、帧长度与视频编解码器图像大小、色彩空间等也需要从avformat_find_stream_info函数得到。


3、int av_read_frame(AVFormatContext *s, AVPacket *pkt);
作用:用于从多媒体文件或多媒体流中读取媒体数据,数据由AVPacket结构pkt来存放。对于音频数据,若是固定比特率,则pkt中装载一个或多个音频帧;若为可变比特率,则pkt中装载一个音频帧。对于视频数据,pkt中装载有一个视频帧。注:当再次调用本函数之前,需使用av_free_packet释放pkt所占用的资源。


4、int av_seek_frame(AVFormatContext *s, int stream_index, int64_t timestamp, int flags);
作用:通过改变媒体文件的读写指针来实现对媒体文件的随机访问,大多源于媒体播放器的快进、快退等功能。
参数:
s:AVFormatContext指针,avformat_open_input返回得到。
stream_index:指定媒体流。
timestamp:时间标签。。
flags:定位方式。


5、void av_close_input_file(AVFormatContext *s);
作用:关闭媒体文件,释放资源,关闭物理IO。


6、AVCodec *avcodec_find_decoder(enum CodecID id);
   AVCodec *avcodec_find_decoder_by_name(const char *name);
作用:根据指定解码器ID或者解码器名称查找相应的解码器并返回AVCodec 。


7、int avcodec_open(AVCodecContext *avctx, AVCodec *codec);
作用:根据输入的AVCodec指针具体化AVCodecContext结构。在调用该函数之前,首先调用avcodec_alloc_context分配一个AVCodecContext结构,或调用avformat_open_input获取媒体文件中对应媒体流的AVCodecContext结构;
此外,通过avcodec_find_decoder获取AVCodec结构。


8、int avcodec_decode_video2(AVCodecContext *avctx,AVFrame *picture,int *got_picture_ptr,AVPacket *avpkt);
作用:解码视频帧。
参数:
avctx:解码器上下文。
picture:输出数据。
got_picture_ptr:指示是否有解码数据输出。
avpkt:输入数据。


9、int avcodec_decode_audio4(AVCodecContext *avctx, AVFrame *frame, int *got_frame_ptr, AVPacket *avpkt);
作用:解码音频帧。输入数据在AVPacket结构中,输出数据在frame中,got_frame_ptr表示是否有数据输出。
参数:
avctx:解码器上下文。
frame:输出数据。
got_frame_ptr:指示是否有解码数据输出。

avpkt:输入数据。


10、int avcodec_close(AVCodecContext *avctx);
作用:关闭解码器,释放avcodec_open中分配的资源。

四、代码流程

 这是来自雷霄骅大神的教程代码《最简单的基于FFmpeg的解码器》

#include <stdio.h>  
  
#define __STDC_CONSTANT_MACROS  
  
extern "C"  
{  
#include "libavcodec/avcodec.h"  
#include "libavformat/avformat.h"  
#include "libswscale/swscale.h"  
};  
  
  
int main(int argc, char* argv[])  
{  
    AVFormatContext *pFormatCtx;  
    int             i, videoindex;  
    AVCodecContext  *pCodecCtx;  
    AVCodec         *pCodec;  
    AVFrame *pFrame,*pFrameYUV;  
    uint8_t *out_buffer;  
    AVPacket *packet;  
    int y_size;  
    int ret, got_picture;  
    struct SwsContext *img_convert_ctx;  
    //输入文件路径  
    char filepath[]="../video/Titanic.ts";  
  
    int frame_cnt;  
  
    av_register_all();//注册所有组件  
    avformat_network_init();  
    pFormatCtx = avformat_alloc_context();  
  
    //打开输入视频文件  
    if(avformat_open_input(&pFormatCtx,filepath,NULL,NULL)!=0){  
        printf("Couldn't open input stream.\n");  
        return -1;  
    }  
    //获取视频文件信息  
    if(avformat_find_stream_info(pFormatCtx,NULL)<0){  
        printf("Couldn't find stream information.\n");  
        return -1;  
    }  
    videoindex=-1;  
    for(i=0; i<pFormatCtx->nb_streams; i++)   
        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){  
            videoindex=i;//找到视频的数组位置  
            break;  
        }  
    if(videoindex==-1){  
        printf("Didn't find a video stream.\n");  
        return -1;  
    }  
  
    pCodecCtx=pFormatCtx->streams[videoindex]->codec;  
    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);//查找解码器  
    if(pCodec==NULL){  
        printf("Codec not found.\n");  
        return -1;  
    }  
    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0){//打开解码器  
        printf("Could not open codec.\n");  
        return -1;  
    }  
    /* 
     * 在此处添加输出视频信息的代码 
     * 取自于pFormatCtx,使用fprintf() 
     */  
    printf("视频的时长:%dμs\n", pFormatCtx->duration);//输入视频的时长(以微秒为单位)  
  
  
  
    pFrame=av_frame_alloc();  
    pFrameYUV=av_frame_alloc();  
    out_buffer=(uint8_t *)av_malloc(avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));  
    avpicture_fill((AVPicture *)pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);  
    packet=(AVPacket *)av_malloc(sizeof(AVPacket));  
    //Output Info-----------------------------  
    printf("--------------- File Information ----------------\n");  
    av_dump_format(pFormatCtx,0,filepath,0);  
    printf("-------------------------------------------------\n");  
    img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,   
        pCodecCtx->width, pCodecCtx->height, AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);   
  
    frame_cnt=0;  
    //从输入文件读取一帧压缩数据  
    while(av_read_frame(pFormatCtx, packet)>=0){  
        if(packet->stream_index==videoindex){  
                /* 
                 * 在此处添加输出H264码流的代码 
                 * 取自于packet,使用fwrite() 
                 */  
            ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);//解码一帧压缩数据  
            if(ret < 0){  
                printf("Decode Error.\n");  
                return -1;  
            }  
            if(got_picture){  
                sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,   
                    pFrameYUV->data, pFrameYUV->linesize);  
                printf("Decoded frame index: %d\n",frame_cnt);  
  
                /* 
                 * 在此处添加输出YUV的代码 
                 * 取自于pFrameYUV,使用fwrite() 
                 */  
  
                frame_cnt++;  
  
            }  
        }  
        av_free_packet(packet);  
    }  
  
    sws_freeContext(img_convert_ctx);    
  
    av_frame_free(&pFrameYUV);  
    av_frame_free(&pFrame);  
    avcodec_close(pCodecCtx);//关闭解码器  
    avformat_close_input(&pFormatCtx);//关闭输入视频文件。  
  
    return 0;  
}  

查看评论

FFmpeg教程【转】

来自:https://github.com/yinwenjie/FFmpeg_Tutorial FFmpeg工具和sdk库的使用demo 一、使用FFmpeg命令行工具和批处理...
  • chenyefei
  • chenyefei
  • 2016-08-23 12:06:01
  • 9208

FFmpeg教程(一) 视音频基础知识

视频播放器的原理 封装格式 作用:视频码流和音频码流按照一定的格式储存在一个文件汇总 视频编码数据 作用:将视频像素数据(RGB,YUV等)压缩成为视频码流,从而降低视频的数据量 音频码流 ...
  • Bobsweetie
  • Bobsweetie
  • 2016-03-20 08:28:20
  • 13210

ffmpeg教程

ffmpeg教程 http://blog.csdn.net/cffishappy/article/details/7352898 概要  电影文件有很多基本的组成部分。首先,文件...
  • u012803067
  • u012803067
  • 2018-02-05 10:43:40
  • 407

ffmpeg实战教程(十一)手把手教你实现直播功能,不依赖第三方SDK

直播,2016最火的技术之一了,更多的关于直播的知识:http://blog.csdn.net/king1425/article/details/72489272 …这篇我们就不依赖任何集成好的SD...
  • King1425
  • King1425
  • 2017-05-19 20:24:01
  • 5223

FFMPEG教程完美排版.pdf

  • 2015年07月24日 11:13
  • 968KB
  • 下载

ffmpeg的使用

How To Convert MP4 Video File into FLV Format Using FFMPEG:http://stackoverflow.com/questions/850492...
  • dipolar
  • dipolar
  • 2016-12-12 11:06:02
  • 1010

ffdoc (FFMPEG的最完整教程)

  • 2013年10月10日 15:07
  • 824KB
  • 下载

Ubuntu下安装ffmpeg完整教程

http://www.56cto.com/499 这个教程适用于Ubuntu, Debian, 或者 Linux Mint。本次安装包含一些外部FFMPEG编码和解码器安装FFMPEG需要的所有组件...
  • danfengw
  • danfengw
  • 2017-03-17 14:52:21
  • 5169

[总结]FFMPEG视音频编解码零基础学习方法

在CSDN上的这一段日子,接触到了很多同行业的人,尤其是使用FFMPEG进行视音频编解码的人,有的已经是有多年经验的“大神”,有的是刚开始学习的初学者。在和大家探讨的过程中,我忽然发现了一个问题:在“...
  • leixiaohua1020
  • leixiaohua1020
  • 2013-11-16 00:04:05
  • 486115

网络精英出版系统 v2.0 For ASP.NET

  • 2003年01月13日 00:00
  • 1.33MB
  • 下载
    个人资料
    专栏达人 持之以恒
    等级:
    访问量: 67万+
    积分: 6852
    排名: 4268
    博客专栏
    最新评论