zoukankan      html  css  js  c++  java
  • 使用FFMPEG SDK解码流数据

    本文以H264视频流为例,讲解解码流数据的步骤。

    为突出重点,本文只专注于讨论解码视频流数据,不涉及其它(如开发环境的配置等)。如果您需要这方面的信息,请和我联系。


    准备变量 

    定义AVCodecContext。如果您使用类,可以定义成类成员。我这里定义成全局变量。

    static AVCodecContext * g_pCodecCtx = NULL;

    定义一个AVFrame,AVFrame描述一个多媒体帧。解码后的数据将被放在其中。

    static AVFrame * g_pavfFrame = NULL;


    初始化解码器 

    现在开始初始化您的解码器。我把整个初始化过程包在了一个函数里,除非您有更好的主意,我建议您也这么做。函数长得象这样:

    BOOL H264_Init()

    {

    }

    初始化libavcodec,MMPEG要求,这个函数一定要第一个被调用:

    avcodec_init();

    挂上所有的codec。也许只挂一个H264的codec就行,我没试过:

    av_register_all();

    得到H264的解码器:

    AVCodec * pCodec = avcodec_find_decoder(CODEC_ID_H264);

    创建一个AVCodecContext,并用默认值初始化:

    g_pCodecCtx = avcodec_alloc_context();

    更改g_pCodecCtx的一些成员变量的值,您应该从解码方得到这些变量值:

    g_pCodecCtx->time_base.num = 1; //这两行:一秒钟25帧

    g_pCodecCtx->time_base.den = 25;

    g_pCodecCtx->bit_rate = 0; //初始化为0

    g_pCodecCtx->frame_number = 1; //每包一个视频帧

    g_pCodecCtx->codec_type = CODEC_TYPE_VIDEO;

    g_pCodecCtx->width = 704; //这两行:视频的宽度和高度

    g_pCodecCtx->height = 576;

    打开codec。如果打开成功的话,分配AVFrame:

    if(avcodec_open(g_pCodecCtx, pCodec) >= 0)

    {

    g_pavfFrame = avcodec_alloc_frame();// Allocate video frame

    }

    列出完整的初始化解码库的代码:

    image


    解码 

    如果您只要求解成YUV 420I数据,只需一次调用就可以了:

    avcodec_decode_video(g_pCodecCtx, g_pavfFrame, (int *)&nGot, (unsigned __int8 *)pSrcData, dwDataLen);

    这里,nGot用来返回解码成功与否,avcodec_decode_video调用完成后,如果nGot不等于0,则表示解码成功,否则未解出视频帧。

    pSrcData是待解的H264编码的一段数据流,dwDataLen表示该段数据流的长度,单位是byte。

    解码后的视频帧(YUV数据)被存入g_pavfFrame,g_pavfFrame->data[0]、g_pavfFrame->data[1]、g_pavfFrame->data[2]即是YUV数据。下面的示例代码把YUV数据压在了一块内存里,排列方式为:

    YY

    YY

    U

    V

    该函数有返回值:如果解码成功,则返回本次解码使用的码流字节数,否则返回0。为简单起见,我这里假设pSrcData只包含一个视频帧。

    同样,出于模块化的要求和代码维护的方便,我把解码动作也包在了一个函数里:

    BOOL H264_Decode(const PBYTE pSrcData, const DWORD dwDataLen, PBYTE pDeData, int * pnWidth, int * pnHeight)

    pSrcData – 待解码数据

    dwDataLen – 待解码数据字节数

    pDeData – 用来返回解码后的YUV数据

    pnWidth, pnHeight – 用来返回视频的长度和宽度

    下面列出完整的代码:

    image


    释放解码器 

    以上其实已经完成了本文的任务,但从负责任的角度,要善始善终嘛。

    释放的过程没什么好说的,一看就明白。同样,我也把它们包在了一个函数里:

    image

    (抱歉的很,文章本来是用Word写的,代码块是一个个文本框,但贴到这里却变成了图片。)


     下面是如果解码以及将 YV12 数据转换成 
    32 位 ARGB 数据的代码

    2 #include "avcodec.h"
    3 #include "h264decoder.h";

    5 typedef unsigned char byte_t;
    6 typedef unsigned int uint_t;

    8 struct AVCodec *fCodec = NULL; // Codec
    9 struct AVCodecContext *fCodecContext = NULL; // Codec Context
    10 struct AVFrame *fVideoFrame = NULL; // Frame 
    11 
    12 int fDisplayWidth = 0;
    13 int fDisplayHeight = 0;
    14 int *fColorTable = NULL;
    15 
    16 int avcodec_decode_video(AVCodecContext *avctx, AVFrame *picture,
    17 int *got_picture_ptr,
    18 const uint8_t *buf, int buf_size)
    19 {
    20 AVPacket avpkt;
    21 av_init_packet(&avpkt);
    22 avpkt.data = buf;
    23 avpkt.size = buf_size;
    24 // HACK for CorePNG to decode as normal PNG by default
    25 avpkt.flags = AV_PKT_FLAG_KEY;
    26 return avcodec_decode_video2(avctx, picture, got_picture_ptr, &avpkt);
    27 }
    28 
    29 #define RGB_V(v) ((v < 0) ? 0 : ((v > 255) ? 255 : v))
    30 
    31 void DeleteYUVTable()
    32 {
    33 av_free(fColorTable);
    34 }
    35 
    36 void CreateYUVTable()
    37 {
    38 int i;
    39 int u, v;
    40 int *u_b_tab = NULL;
    41 int *u_g_tab = NULL;
    42 int *v_g_tab = NULL;
    43 int *v_r_tab = NULL;
    44 
    45 fColorTable = (int *)av_malloc(4 * 256 * sizeof(int));
    46 u_b_tab = &fColorTable[0 * 256];
    47 u_g_tab = &fColorTable[1 * 256];
    48 v_g_tab = &fColorTable[2 * 256];
    49 v_r_tab = &fColorTable[3 * 256];
    50 
    51 for (i = 0; i < 256; i++) {
    52 u = v = (i - 128);
    53 u_b_tab[i] = (int) ( 1.772 * u);
    54 u_g_tab[i] = (int) ( 0.34414 * u);
    55 v_g_tab[i] = (int) ( 0.71414 * v); 
    56 v_r_tab[i] = (int) ( 1.402 * v);
    57 }
    58 }
    59 
    60 /** YV12 To RGB888 */
    61 void DisplayYUV_32(uint_t *displayBuffer, int videoWidth, int videoHeight, int outPitch)
    62 {
    63 int *u_b_tab = &fColorTable[0 * 256];
    64 int *u_g_tab = &fColorTable[1 * 256];
    65 int *v_g_tab = &fColorTable[2 * 256];
    66 int *v_r_tab = &fColorTable[3 * 256];
    67 
    68 // YV12: [Y:MxN] [U:M/2xN/2] [V:M/2xN/2]
    69 byte_t* y = fVideoFrame->data[0];
    70 byte_t* u = fVideoFrame->data[1];
    71 byte_t* v = fVideoFrame->data[2];
    72 
    73 int src_ystride = fVideoFrame->linesize[0];
    74 int src_uvstride = fVideoFrame->linesize[1];
    75 
    76 int i, line;
    77 int r, g, b;
    78 
    79 int ub, ug, vg, vr;
    80 
    81 int width = videoWidth;
    82 int height = videoHeight;
    83 
    84 // 剪切边框
    85 if (width > fDisplayWidth) {
    86 width = fDisplayWidth; 
    87 y += (videoWidth - fDisplayWidth) / 2;
    88 u += (videoWidth - fDisplayWidth) / 4;
    89 v += (videoWidth - fDisplayWidth) / 4;
    90 }
    91 
    92 if (height > fDisplayHeight) {
    93 height = fDisplayHeight;
    94 }
    95 
    96 for (line = 0; line < height; line++) {
    97 byte_t* yoff = y + line * src_ystride;
    98 byte_t* uoff = u + (line / 2) * src_uvstride;
    99 byte_t* voff = v + (line / 2) * src_uvstride;
    100 //uint_t* buffer = displayBuffer + (height - line - 1) * outPitch;
    101 uint_t* buffer = displayBuffer + line * outPitch;
    102 
    103 for (i = 0; i < width; i++) {
    104 ub = u_b_tab[*uoff];
    105 ug = u_g_tab[*uoff];
    106 vg = v_g_tab[*voff];
    107 vr = v_r_tab[*voff];
    108 
    109 b = RGB_V(*yoff + ub);
    110 g = RGB_V(*yoff - ug - vg);
    111 r = RGB_V(*yoff + vr);
    112 
    113 *buffer = 0xff000000 | b << 16 | g << 8 | r;
    114 
    115 buffer++;
    116 yoff ++;
    117 
    118 if ((i % 2) == 1) {
    119 uoff++;
    120 voff++;
    121 }
    122 }
    123 }
    124 }
    125 
    126 int avc_decode_init(int width, int height)
    127 {
    128 if (fCodecContext != NULL) {
    129 return 0;
    130 }
    131 avcodec_init(); 
    132 avcodec_register_all();
    133 fCodec = avcodec_find_decoder(CODEC_ID_H264);
    134 
    135 fDisplayWidth = width;
    136 fDisplayHeight = height;
    137 
    138 CreateYUVTable(); 
    139 
    140 fCodecContext = avcodec_alloc_context(); 
    141 avcodec_open(fCodecContext, fCodec); 
    142 fVideoFrame = avcodec_alloc_frame();
    143 
    144 return 1;
    145 }
    146 
    147 int avc_decode_release()
    148 {
    149 if (fCodecContext) {
    150 avcodec_close(fCodecContext);
    151 free(fCodecContext->priv_data);
    152 free(fCodecContext);
    153 fCodecContext = NULL;
    154 }
    155 
    156 if (fVideoFrame) {
    157 free(fVideoFrame);
    158 fVideoFrame = NULL;
    159 }
    160 
    161 DeleteYUVTable();
    162 return 1;
    163 }
    164 
    165 int avc_decode(char* buf, int nalLen, char* out)
    166 {
    167 byte_t* data = (byte_t*)buf;
    168 int frameSize = 0;
    169 
    170 int ret = avcodec_decode_video(fCodecContext, fVideoFrame, &frameSize, data, nalLen); 
    171 if (ret <= 0) {
    172 return ret;
    173 }
    174 
    175 int width = fCodecContext->width;
    176 int height = fCodecContext->height;
    177 DisplayYUV_32((uint32_t*)out, width, height, fDisplayWidth);
    178 return ret; 
    179 }

  • 相关阅读:
    tshark的命令使用
    svn log查看自己提交的记录
    账号安全 syyh
    Trivy 容器镜像扫描工具学习 syyh
    《关键对话》脑图整理 syyh
    Grafana 任意文件读取漏洞 (CVE202143798)学习 syyh
    容器安全管理 syyh
    【Sass/SCSS】我花4小时整理了的Sass的函数
    【JavaScript使用技巧】三个截取字符串中的子串,你用的哪个
    【SVG】为了前端页面的美丽,我选择学习SVG
  • 原文地址:https://www.cnblogs.com/ting5/p/5057049.html
Copyright © 2011-2022 走看看