代码之家  ›  专栏  ›  技术社区  ›  Heiner

用libav/ffmpeg替换bento4

  •  -1
  • Heiner  · 技术社区  · 6 年前

    我们使用Bento4(一个设计得非常好的SDK)在.mov容器中解复用mp4文件解码由自己的编解码器完成,因此只需要原始(帧内)样本。到现在为止,这很简单

    AP4_Track *test_videoTrack = nullptr;
    AP4_ByteStream *input = nullptr;
    AP4_Result result = AP4_FileByteStream::Create(filename, AP4_FileByteStream::STREAM_MODE_READ, input);
    
    AP4_File m_file (*input, true);
    
    //
    // Read movie tracks, and metadata, find the video track
    size_t index = 0;
    uint32_t m_width = 0, m_height = 0;
    auto item = m_file.GetMovie()->GetTracks().FirstItem();
    auto track = item->GetData();
    if (track->GetType() == AP4_Track::TYPE_VIDEO) 
    {
        m_width = (uint32_t)((double)test_videoTrack->GetWidth() / double(1 << 16));
        m_height = (uint32_t)((double)test_videoTrack->GetHeight() / double(1 << 16));
    
        std::string codec("unknown");
        auto sd = track->GetSampleDescription(0);
        AP4_String c;
        if (AP4_SUCCEEDED(sd->GetCodecString(c))) 
        {
            codec = c.GetChars();
        }
    
        // Find and instantiate the decoder
        AP4_Sample sample;
        AP4_DataBuffer sampleData;
        test_videoTrack->ReadSample(0, sample, sampleData);
    }
    

    出于几个原因,我们希望用libav/ffmpeg替换bento4(主要是因为我们已经在项目中,希望减少依赖性)

    我们如何(最好是在伪代码中)用libav替换上面完成的bento4任务?请记住,使用的编解码器不在ffmpeg库中,因此我们不能使用标准的ffmpeg解码示例打开媒体文件只是失败没有解码器,到目前为止我们还没有尺寸或任何其他信息我们需要的是

    • 打开媒体文件
    • 获取包含的曲目(可能还有音频)
    • 获取曲目大小/长度信息
    • 按索引获取跟踪样本
    1 回复  |  直到 6 年前
        1
  •  0
  •   Heiner    6 年前

    结果很简单:

    AVFormatContext* inputFile = avformat_alloc_context();
    avformat_open_input(&inputFile, filename, nullptr, nullptr);
    avformat_find_stream_info(inputFile, nullptr);
    
    //Get just two streams...First Video & First Audio
    int videoStreamIndex = -1, audioStreamIndex = -1;
    for (int i = 0; i < inputFile->nb_streams; i++)
    {
        if (inputFile->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO && videoStreamIndex == -1)
        {
                videoStreamIndex = i;
        }
        else if (inputFile->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && audioStreamIndex == -1)
        {
            audioStreamIndex = i;
        }
    }
    

    现在测试正确的编解码器标记

    // get codec id
    char ct[64] = {0};
    static const char* codec_id = "MPAK";
    av_get_codec_tag_string( ct, sizeof(ct),inputFile->streams[videoStreamIndex]->codec->codec_tag);
    assert(strncmp( ct , codec_id, strlen(codec_id)) == 0)
    

    我不知道大小是在选择编解码器(甚至可用)之前设置的。

    // lookup size
    Size2D mediasize(inputFile->streams[videoStreamIndex]->codec->width, inputFile->streams[videoStreamIndex]->codec->height);
    

    按帧查找并解压缩(视频)的操作如下:

    AVStream* s = m_file->streams[videoStreamIndex];
    int64_t seek_ts = (int64_t(frame_index) * s->r_frame_rate.den *  s->time_base.den) / (int64_t(s->r_frame_rate.num) * s->time_base.num);
    av_seek_frame(m_hap_file, videoStreamIndex,  seek_ts, AVSEEK_FLAG_ANY);
    
    AVPacket pkt;
    av_read_frame(inputFile, &pkt);
    

    现在,这个包包含一个可以用自己的解码器解包的帧。