zoukankan      html  css  js  c++  java
  • 基于网络流音视频包的音视频解码思路

    本篇文章对自己项目中的网络媒体流解码流程进行了梳理和总结。本文中的方法不同于一般打开文件或流进行读写的流程,不需要通过avformat_open_input,avformat_find_stream_info等操作获取AVFormatContext,然后遍历不同流信息。此处直接通过解析音视频sequence header包,获取相应的参数来初始化对应的AVCodec和AVCodecContext,然后使用AVCodecContext进行后续的解码操作。由于项目中直接获取到了音视频包,所以也省去了av_read_frame操作。

    一般流程:

    前提:av_register_all()

    1. 构造AVCodec

    2. 构造AVCodecContext

    3. 解码(注意输入的数据格式)

    音频解码(关键函数 avcodec_decode_audio4):

    1. 构造AVCodec(AAC为例)

    codec = avcodec_find_decoder(AV_CODEC_ID_AAC);

    2. 构造AVCodecContext

    codec_ctx = avcodec_alloc_context3(codec);
    // these params are neccesary when decoding
    codec_ctx->sample_fmt = AV_SAMPLE_FMT_FLTP;
    codec_ctx->sample_rate = 44100;
    codec_ctx->channels = channels;
    codec_ctx->channel_layout = AV_CH_LAYOUT_MONO;
    if (channels == 2) {
        codec_ctx->channel_layout = AV_CH_LAYOUT_STEREO;
    }
    // 可选参数aac audio sequence header,当前不设置可以正常解析
    //codec_ctx->extradata = (uint8_t*)extradata;
    //codec_ctx->extradata_size = extradata_size;
    
    // 别忘了open codec context
    if ((ret=avcodec_open2(codec_ctx, codec, NULL)) < 0) {
        error("avcodec_open2 audio codec(AAC) failed.");
        return ret;
    }

    3. 解码(注意输入的数据格式)

    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.data = (uint8_t*)unit->bytes;
    pkt.size = unit->size;
    frame = av_frame_alloc();
    do { int got_frame = 0; // pkt should be raw aac audio data, that is, without aac header.
    // 纯aac音频数据,不包含任何容器头或编码格式头
    ret = avcodec_decode_audio4(codec_ctx, frame, &got_frame, &pkt); trace("ret=%d, got_frame=%d, decoded frame size=%d", ret, got_frame, frame->linesize[0]); if (ret < 0) { char err[1000]; av_make_error_string(err, 1000, ret); error("avcodec_decode_audio4 failed. err=%s", err); break; } if (!got_frame) { ret = ERROR_AAC_NO_FRAME; error("avcodec_decode_audio4 no frame."); break; } } while (false); av_free_packet(&pkt);

    视频解码(关键函数 avcodec_decode_video2):

    1. 构造AVCodec(H.264为例)

    codec = avcodec_find_decoder(AV_CODEC_ID_H264);

    2. 构造AVCodecContext

    codec_ctx = avcodec_alloc_context3(codec);
    // extradata(video sequence header SPS, PPS) is neccesary when decoding
    codec_ctx->extradata = (uint8_t*)extradata;
    codec_ctx->extradata_size = extradata_size;
    // 别忘了 open codec ctx
    if (avcodec_open2(codec_ctx, codec, NULL) < 0) {
        error("avcodec_open2 video codec(H264) failed.");
        return -1;
    }

    3. 解码(注意输入的数据格式)

    AVPacket pkt;
    av_init_packet(&pkt);
    pkt.data = (uint8_t*)unit->bytes;
    pkt.size = unit->size;
    frame = av_frame_alloc();
    
    do {
        int got_picture = 0;
        // pkt should be NAL unit, that is, with 1 byte header. 
    // 如果是ibmf(iso basic media file format)格式,需要在nalu unit前面加上可变字长的Unit length字段
    // 如果是annexb格式,没有测试过,如果纯nalu数据解码不正常,可以尝试加入nalu的starting code(0x000001/0x00000001)测试。 ret = avcodec_decode_video2(codec_ctx, frame, &got_picture, &pkt); trace("ret=%d, got_picture=%d, decoded frame size=%d", ret, got_picture, frame->linesize[0]*3/2); if (ret < 0) { error("avcodec_decode_video2 failed. ret=%d", ret); break; } if (!got_picture) { ret = ERROR_H264_NO_FRAME; error("avcodec_decode_video2 no frame."); break; } } while (false); av_free_packet(&pkt);
  • 相关阅读:
    C++实现网络寻路
    java实现生日相同概率
    java实现生日相同概率
    Mysql 锁表 for update (引擎/事务)
    mysql(for update)悲观锁总结与实践
    Select For update语句浅析
    Mysql查询语句使用select.. for update导致的数据库死锁分析
    数据库中Select For update语句的解析
    【转载】支付宝运营架构中柔性事务指的是什么?
    互联网支付系统整体架构详解
  • 原文地址:https://www.cnblogs.com/NerdWill/p/6389451.html
Copyright © 2011-2022 走看看