FFmpeg SDK开发课程笔记(一):调用FFmpeg SDK对YUV视频序列进行编码

来源:互联网 发布:嗯淘宝网店教学视频 编辑:程序博客网 时间:2024/06/05 07:15

课程地址 http://edu.csdn.net/course/detail/2515/39428?auto_start=1

需要包含的头文件

#include <iostream>#include <stdio.h>#include "Error.h"extern "C"{    //#include<stdio.h>    #include <stdint.h>    #include <libavcodec/avcodec.h>    #include <libavformat/avformat.h>    #include <libavutil/avutil.h>    #include<libavutil/imgutils.h>    #include <libavutil/opt.h>}

Error.h
就是定义几个出错类型就可以了

/* * Error.h * *  Created on: Aug 14, 2017 *      Author: media */#ifndef ERROR_H_#define ERROR_H_#define IO_FILE_ERROR_READ_FAILED -1#define FF_ERROR_INIT_FAILED -10#define FF_ERROR_ENCODE_FAILED -11#endif /* ERROR_H_ */

定义相关的变量

注意以下均为全局变量

文件路径

const char *inputFileName = NULL;const char *outputFileName = NULL;FILE *pFin = NULL, *pFout = NULL;

视频信息

int frameWidth = 0 , frameHeight = 0;int bitRate = 0, frameToEncode = 0;

ffmpeg中相关的数据结构

AVCodec *codec = NULL;AVCodecContext *codecCtx = NULL;AVFrame *frame = NULL;AVPacket pkt;

处理命令行参数

argv分别为

  1. 输入文件路径
  2. 输出文件路径
  3. 视频宽度
  4. 视频高度
  5. 码率
  6. 需要编码的帧数
static int parse_input_paramaters(int argc, char **argv){    inputFileName=argv[1];    outputFileName=argv[2];    pFin=fopen(inputFileName, "rb+");    if(!pFin)    {        std::cout<<"Error in reading inputfile"<<std::endl;        return IO_FILE_ERROR_READ_FAILED;    }    pFout=fopen(outputFileName, "wb+");    if(!pFout)    {        std::cout<<"Error in reading outputfile"<<std::endl;        return IO_FILE_ERROR_READ_FAILED;    }    frameWidth = atoi(argv[3]);    frameHeight = atoi(argv[4]);    bitRate = atoi(argv[5]);    frameToEncode = atoi(argv[6]);    return 1;}

读取YUV数据

static int read_yuv_data(int color){    /* color = 0 : Y     * color = 1 : U     * color = 2 : V     */    int color_height = color == 0 ? frameHeight : frameHeight/2;    int color_width = color == 0 ? frameWidth : frameWidth/2;    //这里是YUV420P的格式    int color_size=color_height*color_width;    int color_stride=frame->linesize[color];    if(color_width == color_stride)    //这种情况相当于frame->data放满了    {        //fread_s(frame->data[color], color_size, 1, color_size, pFin);        //LINUX下没有fread_s        fread(frame->data[color], color_size, 1, pFin);        /*        fread函数原型:size_t fread(void* buff,size_t size,size_t count,FILE* stream)作用:从文件中读入数据到指定的地址中,ffpempeg里面的AVFrame->data[0,1,2]用于存储YUV数据,所以读到这里参数:第一个参数为接收数据的指针(buff),也即数据存储的地址第二个参数为单个元素的大小,即由指针写入地址的数据大小,注意单位是字节第三个参数为元素个数,即要读取的数据大小为size的元素个素第四个参数为提供数据的文件指针,该指针指向文件内部数据        */    }    else    //这种情况还需要对齐    {        for(int row_idx=0; row_idx<color_height;row_idx++)        {            //fread_s(frame->data[color]+row_idx*color_stride,color_width,1,color_width,pFin);            fread(frame->data[color]+row_idx*color_stride,color_width,1,pFin);        }    }    return pkt.size;}

main 函数

int main(int argv,char **argc){    int got_packet = 0;    if(parse_input_paramaters(argv,argc)>0)    {        std::cout<<"Input file:"<<inputFileName<<std::endl;        std::cout<<"Output file:"<<outputFileName<<std::endl;        std::cout<<"frameWidth:"<<frameWidth<<std::endl;        std::cout<<"frameHeight:"<<frameHeight<<std::endl;        std::cout<<"bitRate:"<<bitRate<<std::endl;        std::cout<<"frameToEncode:"<<frameToEncode<<std::endl;    }    else    {        std::cout<<"Error in cmd line!"<<std::endl;        return -1;    }//处理argv完毕    {//这个大括号似乎是多余的        avcodec_register_all();        //寻找编码器        codec = avcodec_find_encoder(AV_CODEC_ID_H264);        if(!codec)        {            return FF_ERROR_INIT_FAILED;        }        //创建AVCodecContext 结构体,这是一个描述编解码器上下文的数据结构,包含了众多编解码器需要的参数信息,参考http://blog.csdn.net/yuan892173701/article/details/8702333        codecCtx = avcodec_alloc_context3(codec);        if(!codecCtx)        {            return FF_ERROR_INIT_FAILED;        }        codecCtx->width = frameWidth;        codecCtx->height = frameHeight;        codecCtx->bit_rate = bitRate;        AVRational r = {1, 25};        //时间刻度是1/25        codecCtx->time_base = r;        codecCtx->gop_size = 12;        //the number of pictures in a group of pictures, or 0 for intra_only        codecCtx->max_b_frames = 1;        codecCtx->pix_fmt=AV_PIX_FMT_YUV420P;        av_opt_set(codecCtx->priv_data,"preset","slow",0);        //初始化一个视音频编解码器的AVCodecContext        if(avcodec_open2(codecCtx, codec, NULL)<0)        {            return FF_ERROR_INIT_FAILED;        }        //分配AVFrame        frame = av_frame_alloc();        if(!frame)        {            return FF_ERROR_INIT_FAILED;        }        frame->width = codecCtx->width;        frame->height = codecCtx->height;        frame->format = codecCtx->pix_fmt;        if(av_image_alloc(frame->data, frame->linesize, frame->width, frame->height, (AVPixelFormat)frame->format, 32)<0)        {            return FF_ERROR_INIT_FAILED;        }    }    for(int frameIdx = 0; frameIdx <frameToEncode; frameIdx++)    {        //初始化AVPacket        av_init_packet(&pkt);        pkt.data=NULL;        pkt.size=0;        //把YUV数据写入frame->data里面        read_yuv_data(0);        read_yuv_data(1);        read_yuv_data(2);        frame->pts = frameIdx;        if(avcodec_encode_video2(codecCtx, &pkt, frame, &got_packet)<0)        //avcodec_encodec_video2: AVFrame to AVPacket        {            std::cout<<"Error in encoding"<<std::endl;            return FF_ERROR_ENCODE_FAILED;        }        if(got_packet)        {            std::cout<<"Write packet of frame "<<frameIdx<<",size "<<pkt.size<<std::endl;            fwrite(pkt.data, 1, pkt.size, pFout);            av_packet_unref(&pkt);        }        for(got_packet = 1;got_packet;)        {            if(avcodec_encode_video2(codecCtx, &pkt, NULL, &got_packet)<0)            {                std::cout<<"Error in encoding"<<std::endl;                return FF_ERROR_ENCODE_FAILED;            }            if(got_packet)            //有时候帧数据写完了AVPacket里面还有东西            {                if(avcodec_encode_video2(codecCtx, &pkt, frame, &got_packet)<0)                {                    std::cout<<"Write packet of size "<<pkt.size<<std::endl;                    fwrite(pkt.data, 1, pkt.size, pFout);                    av_packet_unref(&pkt);                }            }        }    }    //    fclose(pFin);    fclose(pFout);    //释放内存    avcodec_close(codecCtx);    av_free(codecCtx);    av_freep(frame->data[0]);    av_frame_free(&frame);    std::cout<<"success!"<<std::endl;    return 0;}
原创粉丝点击