ffmpeg - 用 libav/ffmpeg 替换 Bento4

标签 ffmpeg libav

我们使用 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 解码示例。打开媒体文件根本失败。如果没有解码器,到目前为止我们没有大小或任何其他信息。我们需要的是
  • 打开媒体文件
  • 获取包含的轨道(可能还有音频)
  • 获取轨道大小/长度信息
  • 按索引
  • 获取跟踪样本

    最佳答案

    结果很容易:

    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);
    

    现在数据包包含一个准备好用自己的解码器解包的帧。

    关于ffmpeg - 用 libav/ffmpeg 替换 Bento4,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51469670/

    相关文章:

    node.js - 为什么在谷歌云上启动的ffmpeg函数会抛出 "Error: Output stream error: Maximum call stack size exceeded"?

    ffmpeg - 使用 libav 混合可流式分段 mp4

    matlab - 修剪 mp4 文件而不再次编码

    ffmpeg - 创建ffmpeg马赛克时指定视频的开始时间

    android - 在 Android NDK 上使用 ffmpeg 淡入淡出图片

    FFMpeg - 如何将编解码器(视频和音频)从 'mp4' 容器复制到 'ts' 容器

    ios - 单元测试时的链接器错误 : ld: illegal text-relocation to cstring in . .. from _av_image_check_size in .../libavutil.a(imgutils.o)

    ffmpeg - FFmpeg 过滤器图描述清晰

    ffmpeg - avio_set_interrupt_cb 的替代品是什么?

    从 DTS 转码到 AAC 时音频丢失