• WebRTC VideoEngine超详细教程(三)——集成X264编码和ffmpeg解码


    转自:http://blog.csdn.net/nonmarking/article/details/47958395

    本系列目前共三篇文章,后续还会更新

    WebRTC VideoEngine超详细教程(一)——视频通话的基本流程

    WebRTC VideoEngine超详细教程(二)——集成OPENH264编解码器

    WebRTC VideoEngine超详细教程(三)——集成X264编码和ffmpeg解码

    总述

    在前一篇文章中,讲解了如何将OPENH264编解码器集成到WebRTC中,但是OPENH264只能编码baseline的H264视频,而且就编码质量而言,还是X264最好,本文就来讲解一下如何将X264编码器集成到WebRTC中,为了实现解码,同时要用到ffmpeg。总体流程和之前一样,分为重新封装编解码器和注册调用两大步骤,注册调用这一步没有任何不同,主要是重新封装这一步骤有较大区别。

    重新封装X264编码功能

    首先当然还是要下载X264源码编译出相应的库以供调用。在windows下使用mingw进行编译,再使用poxports工具导出库,最后得到libx264.dll和libx264.lib,同时把x264.h和x264_config.h总共四个文件放到工程目录下,并在项目属性中进行相应配置。
     
    使用x264进行视频编码的基本流程如下
    [cpp] view plaincopy
     
    1. #include <stdint.h>  
    2. #include <stdio.h>  
    3. #include <x264.h>  
    4.   
    5. int main( int argc, char **argv )  
    6. {  
    7.     int width, height;  
    8.     x264_param_t param;  
    9.     x264_picture_t pic;  
    10.     x264_picture_t pic_out;  
    11.     x264_t *h;  
    12.     int i_frame = 0;  
    13.     int i_frame_size;  
    14.     x264_nal_t *nal;  
    15.     int i_nal;  
    16.   
    17.     /* Get default params for preset/tuning */  
    18.     if( x264_param_default_preset( &param, "medium", NULL ) < 0 )  
    19.         goto fail;  
    20.   
    21.     /* Configure non-default params */  
    22.     param.i_csp = X264_CSP_I420;  
    23.     param.i_width  = width;  
    24.     param.i_height = height;  
    25.     param.b_vfr_input = 0;  
    26.     param.b_repeat_headers = 1;  
    27.     param.b_annexb = 1;  
    28.   
    29.     /* Apply profile restrictions. */  
    30.     if( x264_param_apply_profile( &param, "high" ) < 0 )  
    31.         goto fail;  
    32.   
    33.     if( x264_picture_alloc( &pic, param.i_csp, param.i_width, param.i_height ) < 0 )  
    34.         goto fail;  
    35.   
    36.     h = x264_encoder_open( &param);  
    37.     if( !h )  
    38.         goto fail;  
    39.   
    40.     int luma_size = width * height;  
    41.     int chroma_size = luma_size / 4;  
    42.     /* Encode frames */  
    43.     for( ;; i_frame++ )  
    44.     {  
    45.         /* Read input frame */  
    46.         if( fread( pic.img.plane[0], 1, luma_size, stdin ) != luma_size )  
    47.             break;  
    48.         if( fread( pic.img.plane[1], 1, chroma_size, stdin ) != chroma_size )  
    49.             break;  
    50.         if( fread( pic.img.plane[2], 1, chroma_size, stdin ) != chroma_size )  
    51.             break;  
    52.   
    53.         pic.i_pts = i_frame;  
    54.         i_frame_size = x264_encoder_encode( h, &nal, &i_nal, &pic, &pic_out );  
    55.         if( i_frame_size < 0 )  
    56.             goto fail;  
    57.         else if( i_frame_size )  
    58.         {  
    59.             if( !fwrite( nal->p_payload, i_frame_size, 1, stdout ) )  
    60.                 goto fail;  
    61.         }  
    62.     }  
    63.     /* Flush delayed frames */  
    64.     while( x264_encoder_delayed_frames( h ) )  
    65.     {  
    66.         i_frame_size = x264_encoder_encode( h, &nal, &i_nal, NULL, &pic_out );  
    67.         if( i_frame_size < 0 )  
    68.             goto fail;  
    69.         else if( i_frame_size )  
    70.         {  
    71.             if( !fwrite( nal->p_payload, i_frame_size, 1, stdout ) )  
    72.                 goto fail;  
    73.         }  
    74.     }  
    75.   
    76.     x264_encoder_close( h );  
    77.     x264_picture_clean( &pic );  
    78.     return 0;  
    79. }  
    还是一样,照葫芦画瓢,改写上一篇文章中提到的H264EncoderImpl类
    首先是类的定义,去掉了原来的私有成员变量ISVCEncoder* encoder_,加入了以下几项,其他内容不变
    [cpp] view plaincopy
     
    1. x264_picture_t pic;  
    2. x264_picture_t pic_out;  
    3. x264_t *encoder_;  
    4. int i_frame = 0;//frame index  
    5. x264_nal_t *nal;  

    相应的,构造函数和析构函数也要改变,这里就不赘述了,重点看InitEncode方法和Encode方法。
    InitEncode方法的实现改写如下
    [cpp] view plaincopy
     
    1. int H264EncoderImpl::InitEncode(const VideoCodec* inst,  
    2.         int number_of_cores,  
    3.         size_t max_payload_size) {  
    4.         if (inst == NULL) {  
    5.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    6.         }  
    7.         if (inst->maxFramerate < 1) {  
    8.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    9.         }  
    10.         // allow zero to represent an unspecified maxBitRate  
    11.         if (inst->maxBitrate > 0 && inst->startBitrate > inst->maxBitrate) {  
    12.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    13.         }  
    14.         if (inst->width < 1 || inst->height < 1) {  
    15.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    16.         }  
    17.         if (number_of_cores < 1) {  
    18.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    19.         }  
    20.   
    21.         int ret_val = Release();  
    22.         if (ret_val < 0) {  
    23.             return ret_val;  
    24.         }  
    25.         /* Get default params for preset/tuning */  
    26.         x264_param_t param;  
    27.         ret_val = x264_param_default_preset(&param, "medium", NULL);  
    28.         if (ret_val != 0) {  
    29.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    30.                 "H264EncoderImpl::InitEncode() fails to initialize encoder ret_val %d",  
    31.                 ret_val);  
    32.             x264_encoder_close(encoder_);  
    33.             encoder_ = NULL;  
    34.             return WEBRTC_VIDEO_CODEC_ERROR;  
    35.         }  
    36.         /* Configure non-default params */  
    37.         param.i_csp = X264_CSP_I420;  
    38.         param.i_width = inst->width;  
    39.         param.i_height = inst->height;  
    40.         param.b_vfr_input = 0;  
    41.         param.b_repeat_headers = 1;  
    42.         param.b_annexb = 0;//这里设置为0,是为了使编码后的NAL统一有4字节的起始码,便于处理,否则会同时有3字节和4字节的起始码,很麻烦  
    43.         param.i_fps_num = 1;  
    44.         param.i_fps_num = codec_.maxFramerate;  
    45.         param.rc.i_bitrate = codec_.maxBitrate;  
    46.         /* Apply profile restrictions. */  
    47.         ret_val = x264_param_apply_profile(&param, "high");  
    48.         if (ret_val != 0) {  
    49.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    50.                 "H264EncoderImpl::InitEncode() fails to initialize encoder ret_val %d",  
    51.                 ret_val);  
    52.             x264_encoder_close(encoder_);  
    53.             encoder_ = NULL;  
    54.             return WEBRTC_VIDEO_CODEC_ERROR;  
    55.         }  
    56.   
    57.         ret_val = x264_picture_alloc(&pic, param.i_csp, param.i_width, param.i_height);  
    58.         if (ret_val != 0) {  
    59.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    60.                 "H264EncoderImpl::InitEncode() fails to initialize encoder ret_val %d",  
    61.                 ret_val);  
    62.             x264_encoder_close(encoder_);  
    63.             encoder_ = NULL;  
    64.             return WEBRTC_VIDEO_CODEC_ERROR;  
    65.         }  
    66.   
    67.         encoder_ = x264_encoder_open(&param);  
    68.         if (!encoder_){  
    69.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    70.                 "H264EncoderImpl::InitEncode() fails to initialize encoder ret_val %d",  
    71.                 ret_val);  
    72.             x264_encoder_close(encoder_);  
    73.             x264_picture_clean(&pic);  
    74.             encoder_ = NULL;  
    75.             return WEBRTC_VIDEO_CODEC_ERROR;  
    76.         }  
    77.   
    78.         if (&codec_ != inst) {  
    79.             codec_ = *inst;  
    80.         }  
    81.   
    82.         if (encoded_image_._buffer != NULL) {  
    83.             delete[] encoded_image_._buffer;  
    84.         }  
    85.         encoded_image_._size = CalcBufferSize(kI420, codec_.width, codec_.height);  
    86.         encoded_image_._buffer = new uint8_t[encoded_image_._size];  
    87.         encoded_image_._completeFrame = true;  
    88.   
    89.         inited_ = true;  
    90.         WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, -1,  
    91.             "H264EncoderImpl::InitEncode(%d, height:%d, framerate:%d, start_bitrate:%d, max_bitrate:%d)",  
    92.             inst->width, inst->height, inst->maxFramerate, inst->startBitrate, inst->maxBitrate);  
    93.   
    94.         return WEBRTC_VIDEO_CODEC_OK;  
    95.     }  

    Encode方法的实现改写如下
    [cpp] view plaincopy
     
    1. int H264EncoderImpl::Encode(const I420VideoFrame& input_image,  
    2.         const CodecSpecificInfo* codec_specific_info,  
    3.         const std::vector<VideoFrameType>* frame_types) {  
    4.         if (!inited_) {  
    5.             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;  
    6.         }  
    7.         if (input_image.IsZeroSize()) {  
    8.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    9.         }  
    10.         if (encoded_complete_callback_ == NULL) {  
    11.             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;  
    12.         }  
    13.   
    14.         VideoFrameType frame_type = kDeltaFrame;  
    15.         // We only support one stream at the moment.  
    16.         if (frame_types && frame_types->size() > 0) {  
    17.             frame_type = (*frame_types)[0];  
    18.         }  
    19.   
    20.         bool send_keyframe = (frame_type == kKeyFrame);  
    21.         if (send_keyframe) {  
    22.             pic.b_keyframe = TRUE;  
    23.             WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, -1,  
    24.                 "H264EncoderImpl::EncodeKeyFrame(%d, height:%d)",  
    25.                 input_image.width(), input_image.height());  
    26.         }  
    27.   
    28.         // Check for change in frame size.  
    29.         if (input_image.width() != codec_.width ||  
    30.             input_image.height() != codec_.height) {  
    31.             int ret = UpdateCodecFrameSize(input_image);  
    32.             if (ret < 0) {  
    33.                 return ret;  
    34.             }  
    35.         }  
    36.   
    37.         /* Read input frame */  
    38.         pic.img.plane[0] = const_cast<uint8_t*>(input_image.buffer(kYPlane));  
    39.         pic.img.plane[1] = const_cast<uint8_t*>(input_image.buffer(kUPlane));  
    40.         pic.img.plane[2] = const_cast<uint8_t*>(input_image.buffer(kVPlane));  
    41.         pic.i_pts = i_frame;  
    42.   
    43.         int i_nal = 0;  
    44.         int i_frame_size = x264_encoder_encode(encoder_, &nal, &i_nal, &pic, &pic_out);  
    45.         if (i_frame_size < 0)  
    46.         {  
    47.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    48.                 "H264EncoderImpl::Encode() fails to encode %d",  
    49.                 i_frame_size);  
    50.             x264_encoder_close(encoder_);  
    51.             x264_picture_clean(&pic);  
    52.             encoder_ = NULL;  
    53.             return WEBRTC_VIDEO_CODEC_ERROR;  
    54.         }  
    55.   
    56.         RTPFragmentationHeader frag_info;  
    57.           
    58.         if (i_frame_size)  
    59.         {  
    60.             if (i_nal == 0) {  
    61.                 return WEBRTC_VIDEO_CODEC_OK;  
    62.             }  
    63.             frag_info.VerifyAndAllocateFragmentationHeader(i_nal);  
    64.   
    65.             encoded_image_._length = 0;  
    66.   
    67.             uint32_t totalNaluIndex = 0;  
    68.             for (int nal_index = 0; nal_index < i_nal; nal_index++)  
    69.             {  
    70.                 uint32_t currentNaluSize = 0;  
    71.                 currentNaluSize = nal[nal_index].i_payload - 4; //x264_encoder_encode编码得到的nal单元是已经带有起始码的,此外,这里直接使用nal[index]即可,不必再使用x264_nal_encode函数  
    72.                 memcpy(encoded_image_._buffer + encoded_image_._length, nal[nal_index].p_payload + 4, currentNaluSize);//encoded_image_中存有的是去掉起始码的数据  
    73.                 encoded_image_._length += currentNaluSize;  
    74.   
    75.                 WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, -1,  
    76.                     "H264EncoderImpl::Encode() nal_type %d, length:%d",  
    77.                     nal[nal_index].i_type, encoded_image_._length);  
    78.   
    79.                 frag_info.fragmentationOffset[totalNaluIndex] = encoded_image_._length - currentNaluSize;  
    80.                 frag_info.fragmentationLength[totalNaluIndex] = currentNaluSize;  
    81.                 frag_info.fragmentationPlType[totalNaluIndex] = nal[nal_index].i_type;  
    82.                 frag_info.fragmentationTimeDiff[totalNaluIndex] = 0;  
    83.                 totalNaluIndex++;  
    84.             }  
    85.         }  
    86.         i_frame++;  
    87.         if (encoded_image_._length > 0) {  
    88.             encoded_image_._timeStamp = input_image.timestamp();  
    89.             encoded_image_.capture_time_ms_ = input_image.render_time_ms();  
    90.             encoded_image_._encodedHeight = codec_.height;  
    91.             encoded_image_._encodedWidth = codec_.width;  
    92.             encoded_image_._frameType = frame_type;  
    93.             // call back  
    94.             encoded_complete_callback_->Encoded(encoded_image_, NULL, &frag_info);  
    95.         }  
    96.         return WEBRTC_VIDEO_CODEC_OK;  
    97.     }  

    其他方法的实现均没有改变。
    至此,X264编码器重新封装完毕,还是比较好理解的。

    重新封装ffmpeg解码功能

    首先还是一样,获得ffmpeg的头文件和库文件,加入工程中并进行相应设置,这里只需使用avcodec avformat avutil swscale四个库,头文件也可以做相应的删减。
    ffmpeg解码的基本流程如下,实际集成之后是从WebRTC的EncodedImage& input_image中获得待解码数据的,所以不能使用常见的基于文件的解码流程
    [cpp] view plaincopy
     
    1. AVCodec *codec = avcodec_find_decoder(AV_CODEC_ID_H264);  
    2. AVCodecContext *codecCtx = avcodec_alloc_context3(codec);  
    3. avcodec_open2(codecCtx, codec, nil);  
    4. char *videoData;  
    5. int len;  
    6. AVFrame *frame = av_frame_alloc();  
    7. AVPacket packet;  
    8. av_new_packet(&packet, len);  
    9. memcpy(packet.data, videoData, len);  
    10. int ret, got_picture;  
    11. ret = avcodec_decode_video2(codecCtx, frame, &got_picture, &packet);  
    12. if (ret > 0){  
    13.     if(got_picture){  
    14.     //进行下一步的处理  
    15.     }  
    16. }  
    相应的,对H264DecoderImpl类的定义和各方法的实现要进行改写。
    首先是类的定义,去掉了ISVCDecoder* decoder_,加入了以下私有成员变量
    [cpp] view plaincopy
     
    1. AVCodecContext  *pCodecCtx;  
    2.   AVCodec           *pCodec;  
    3.   AVFrame   *pFrame, *pFrameYUV;  
    4.   AVPacket *packet;  
    5.   struct SwsContext *img_convert_ctx;  
    6.   uint8_t *decode_buffer;//存储最开始收到的SPS、PPS和IDR帧以便进行最开始的解码  
    7.   uint8_t *out_buffer;  
    8.   int framecnt = 0;  
    9.   int encoded_length = 0;  
    构造函数和析构函数的改写省略不表,重点看一下InitDecode方法和Decode方法
    InitDecode方法改写如下
    [cpp] view plaincopy
     
    1. int H264DecoderImpl::InitDecode(const VideoCodec* inst, int number_of_cores) {  
    2.         if (inst == NULL) {  
    3.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    4.         }  
    5.         int ret_val = Release();  
    6.         if (ret_val < 0) {  
    7.             return ret_val;  
    8.         }  
    9.   
    10.         if (&codec_ != inst) {  
    11.             // Save VideoCodec instance for later; mainly for duplicating the decoder.  
    12.             codec_ = *inst;  
    13.         }  
    14.         pCodec = avcodec_find_decoder(AV_CODEC_ID_H264);  
    15.         pCodecCtx = avcodec_alloc_context3(pCodec);  
    16.         pCodecCtx->pix_fmt = PIX_FMT_YUV420P;  
    17.         pCodecCtx->width = codec_.width;  
    18.         pCodecCtx->height = codec_.height;  
    19.         //pCodecCtx->bit_rate = codec_.targetBitrate*1000;  
    20.         pCodecCtx->time_base.num = 1;  
    21.         pCodecCtx->time_base.den = codec_.maxFramerate;  
    22.   
    23.         if (pCodec == NULL){  
    24.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    25.                 "H264DecoderImpl::InitDecode, Codec not found.");  
    26.             return WEBRTC_VIDEO_CODEC_ERROR;  
    27.         }  
    28.         if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){  
    29.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    30.                 "H264DecoderImpl::InitDecode, Could not open codec.");  
    31.             return WEBRTC_VIDEO_CODEC_ERROR;  
    32.         }  
    33.         inited_ = true;  
    34.   
    35.         // Always start with a complete key frame.  
    36.         key_frame_required_ = true;  
    37.         WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, -1,  
    38.             "H264DecoderImpl::InitDecode(%d, height:%d, framerate:%d, start_bitrate:%d, max_bitrate:%d)",  
    39.             inst->width, inst->height, inst->maxFramerate, inst->startBitrate, inst->maxBitrate);  
    40.         return WEBRTC_VIDEO_CODEC_OK;  
    41.     }  
    Decode方法的实现改写如下
    [cpp] view plaincopy
     
    1. int H264DecoderImpl::Decode(const EncodedImage& input_image,  
    2.         bool missing_frames,  
    3.         const RTPFragmentationHeader* fragmentation,  
    4.         const CodecSpecificInfo* codec_specific_info,  
    5.         int64_t /*render_time_ms*/) {  
    6.         if (!inited_) {  
    7.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    8.                 "H264DecoderImpl::Decode, decoder is not initialized");  
    9.             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;  
    10.         }  
    11.   
    12.         if (decode_complete_callback_ == NULL) {  
    13.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    14.                 "H264DecoderImpl::Decode, decode complete call back is not set");  
    15.             return WEBRTC_VIDEO_CODEC_UNINITIALIZED;  
    16.         }  
    17.   
    18.         if (input_image._buffer == NULL) {  
    19.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    20.                 "H264DecoderImpl::Decode, null buffer");  
    21.             return WEBRTC_VIDEO_CODEC_ERR_PARAMETER;  
    22.         }  
    23.         if (!codec_specific_info) {  
    24.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    25.                 "H264EncoderImpl::Decode, no codec info");  
    26.             return WEBRTC_VIDEO_CODEC_ERROR;  
    27.         }  
    28.         if (codec_specific_info->codecType != kVideoCodecH264) {  
    29.             WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    30.                 "H264EncoderImpl::Decode, non h264 codec %d", codec_specific_info->codecType);  
    31.             return WEBRTC_VIDEO_CODEC_ERROR;  
    32.         }  
    33.   
    34.         WEBRTC_TRACE(webrtc::kTraceApiCall, webrtc::kTraceVideoCoding, -1,  
    35.             "H264DecoderImpl::Decode(frame_type:%d, length:%d",  
    36.             input_image._frameType, input_image._length);  
    37.       
    38.         if (framecnt < 2)  
    39.         {//存储最开始的SPS PPS 和 IDR帧以便进行初始的解码  
    40.             memcpy(decode_buffer + encoded_length, input_image._buffer, input_image._length);  
    41.             encoded_length += input_image._length;  
    42.             framecnt++;  
    43.         }  
    44.         else  
    45.         {  
    46.             pFrame = av_frame_alloc();  
    47.             pFrameYUV = av_frame_alloc();  
    48.             out_buffer = (uint8_t *)av_malloc(avpicture_get_size(PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height));  
    49.             avpicture_fill((AVPicture *)pFrameYUV, out_buffer, PIX_FMT_YUV420P, pCodecCtx->width, pCodecCtx->height);  
    50.             img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height, pCodecCtx->pix_fmt,  
    51.                 pCodecCtx->width, pCodecCtx->height, PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);  
    52.               
    53.             if (framecnt == 2)  
    54.             {  
    55.                 packet = (AVPacket *)av_malloc(sizeof(AVPacket));  
    56.                 av_new_packet(packet, encoded_length);  
    57.                 memcpy(packet->data, decode_buffer, encoded_length);  
    58.                 av_free(decode_buffer);  
    59.                 framecnt++;  
    60.                 printf(" Loading");  
    61.             }  
    62.             else  
    63.             {  
    64.                 packet = (AVPacket *)av_malloc(sizeof(AVPacket));  
    65.                 av_new_packet(packet, input_image._length);  
    66.                 memcpy(packet->data, input_image._buffer, input_image._length);  
    67.             }  
    68.               
    69.             int got_picture = 0;  
    70.             int ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture, packet);  
    71.             if (ret < 0){  
    72.                 WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCoding, -1,  
    73.                     "H264DecoderImpl::Decode, Decode Error.");  
    74.                 return WEBRTC_VIDEO_CODEC_ERROR;  
    75.             }  
    76.             if (got_picture){  
    77.                 sws_scale(img_convert_ctx, (const uint8_t* const*)pFrame->data, pFrame->linesize, 0, pCodecCtx->height,  
    78.                     pFrameYUV->data, pFrameYUV->linesize);  
    79.   
    80.                 int size_y = pFrameYUV->linesize[0] * pCodecCtx->height;  
    81.                 int size_u = pFrameYUV->linesize[1] * pCodecCtx->height / 2;  
    82.                 int size_v = pFrameYUV->linesize[2] * pCodecCtx->height / 2;  
    83.   
    84.                 decoded_image_.CreateFrame(size_y, static_cast<uint8_t*>(pFrameYUV->data[0]),  
    85.                     size_u, static_cast<uint8_t*>(pFrameYUV->data[1]),  
    86.                     size_v, static_cast<uint8_t*>(pFrameYUV->data[2]),  
    87.                     pCodecCtx->width,  
    88.                     pCodecCtx->height,  
    89.                     pFrameYUV->linesize[0],  
    90.                     pFrameYUV->linesize[1],  
    91.                     pFrameYUV->linesize[2]);  
    92.   
    93.                 decoded_image_.set_timestamp(input_image._timeStamp);  
    94.                 decode_complete_callback_->Decoded(decoded_image_);  
    95.                 return WEBRTC_VIDEO_CODEC_OK;  
    96.             }  
    97.             else  
    98.                 printf(".");  
    99.             av_free_packet(packet);  
    100.         }  
    101.         return WEBRTC_VIDEO_CODEC_OK;  
    102.     }  

    其他方法的实现保持不变,至此ffmpeg解码功能的重新封装也完成了。
     
    从最后实现的效果来看,X264的视频质量的确是最好的,但是播放端的解码延时比较高,暂时还不清楚原因,希望了解的朋友指教。
    本项目源代码
  • 相关阅读:
    python学习笔记——拾
    python学习笔记——玖
    Python 实现栈与队列
    Vijos1774 机器翻译 [模拟]
    Vijos1788 第K大 [模拟]
    Python 序列求和
    HDU 2102 A计划 DFS与BFS两种写法 [搜索]
    Python 多组输入
    Python 文件读写
    HDU 2068 RPG错排 [错排公式]
  • 原文地址:https://www.cnblogs.com/x_wukong/p/4880961.html
Copyright © 2020-2023  润新知