Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 使用FFmpeg API动态更新mp4_C_Ffmpeg_Mp4_Codec_Transcoding - Fatal编程技术网

C 使用FFmpeg API动态更新mp4

C 使用FFmpeg API动态更新mp4,c,ffmpeg,mp4,codec,transcoding,C,Ffmpeg,Mp4,Codec,Transcoding,我的目标是流出MPEG。作为输入,我获取一个mp4文件流。也就是说,视频制作人将mp4文件写入我尝试使用的流中。视频可能在一分钟到十分钟之间。因为生产者将字节写入流中,所以最初写入的mp4报头不完整(ftyp之前的前32个字节是0x00,因为它还不知道各种偏移量…我认为是录制后写入的): 这是典型mp4的标题的外观: 00 00 00 18 66 74 79 70 69 73 6f 6d 00 00 00 00 ....ftypisom.... 69 73 6f 6d 33

我的目标是流出MPEG。作为输入,我获取一个mp4文件流。也就是说,视频制作人将mp4文件写入我尝试使用的流中。视频可能在一分钟到十分钟之间。因为生产者将字节写入流中,所以最初写入的mp4报头不完整(ftyp之前的前32个字节是0x00,因为它还不知道各种偏移量…我认为是录制后写入的):

这是典型mp4的标题的外观:

00 00 00 18   66 74 79 70   69 73 6f 6d   00 00 00 00   ....ftypisom.... 
69 73 6f 6d   33 67 70 34   00 01 bb 8c   6d 64 61 74   isom3gp4..»Œmdat
00 00 00 00   66 74 79 70   69 73 6f 6d   00 00 00 00   ....ftypisom.... 
69 73 6f 6d   33 67 70 34   00 00 00 18   3f 3f 3f 3f   isom3gp4....????
6d 64 61 74                                             mdat
这是“进行中”mp4的标题的外观:

00 00 00 18   66 74 79 70   69 73 6f 6d   00 00 00 00   ....ftypisom.... 
69 73 6f 6d   33 67 70 34   00 01 bb 8c   6d 64 61 74   isom3gp4..»Œmdat
00 00 00 00   66 74 79 70   69 73 6f 6d   00 00 00 00   ....ftypisom.... 
69 73 6f 6d   33 67 70 34   00 00 00 18   3f 3f 3f 3f   isom3gp4....????
6d 64 61 74                                             mdat
这是我的猜测,但我假设一旦制作人完成录制,它就会通过写入所有必要的偏移量来更新标题

我在努力实现这一目标时遇到了两个问题:

  • 我创建了一个带有读取功能的自定义AVIO,它不支持搜索。在我的驱动程序中,我决定流式处理一个格式正确的mp4文件。我能够检测到它的输入格式。当我试图打开它时,我看到我的自定义读取函数在avformat_open_输入中执行,直到整个文件被读入 我的代码示例:

    av_register_all();
    
    AVFormatContext* pCtx = avformat_alloc_context();
    pCtx->pb = avio_alloc_context(
        pBuffer,         // internal buffer
        iBufSize,        // internal buffer size
        0,               // bWriteable (1=true,0=false)
        stream,          // user data ; will be passed to our callback functions
        read_stream,     // read callback function
        NULL,            // write callback function (not used in this example)
        NULL             // seek callback function
    );
    pCtx->pb->seekable = 0;
    pCtx->pb->write_flag = 0;
    pCtx->iformat = av_find_input_format( "mp4" );
    pCtx->flags |= AVFMT_FLAG_CUSTOM_IO;
    
    avformat_open_input( &pCtx, "", pCtx->iformat, NULL );
    
    显然,这不符合我的需要(我的预期是错误的)。一旦我将有限大小的文件替换为不同长度的流,我就不能让avformat_open_输入在尝试进行进一步处理之前等待流完成

    因此,我需要找到一种方法来打开输入而不尝试读取它,并且只在执行av_read_frame时读取。使用自定义AVIO是否可以做到这一点。即,准备/打开输入->将初始输入数据读取到输入缓冲区->从输入缓冲区读取帧/数据包->将数据包写入输出->重复读取输入数据直到流结束

    我确实清理了google,只看到了两种选择:提供自定义URLProtocol和使用AVFMT(nou文件)

    自定义URL协议
    这听起来有点像是我想要完成的事情的倒退。我知道最好在有可用的文件源时使用它。而我正试图从字节流中读取数据。另外,我认为它不适合我的另一个原因是自定义URLProtocol需要编译成ffmpeg lib,对吗?或者有没有办法在运行时手动注册它

    AVFMT NOFILE
    这似乎是最适合我的事情。该标志本身表示没有底层源文件,并假设我将处理输入数据的所有读取和设置。问题是到目前为止我还没有看到任何在线代码片段,但我的假设如下:

    我真的很希望从任何人那里得到一些关于大脑食物的建议,因为我是ffmpeg和数字媒体的新手,我的第二期希望我能在摄取输入的同时输出流

  • 如上所述,我对mp4文件ByTestStream有一个句柄,因为它将被写入硬盘。格式为mp4(h.264和aac)。我需要在将其流出来之前将其重新复制到mpegts。这应该不难,因为mp4和MPGT只是容器。据我目前所知,mp4文件如下所示:

    [标题信息包含格式版本]
    mdat
    [流数据,在我的例子中是h.264和aac流]
    [一些拖车分离器]
    [拖车数据]

  • 如果这是正确的,我应该能够通过简单地开始读取“mdat”标识符之后的流来获得h.264和aac交织数据的句柄,对吗

    如果这是真的,并且我决定使用AVFMT_NOFILE方法来管理输入数据,我可以直接接收流数据(到AVFormatContext缓冲区)->av_read_frame->处理它->用更多数据填充AVFormatContext->av_read_frame->等等,直到流结束


    我知道,这是一个满嘴我的想法,但我会感谢任何讨论,指针,想法

    好的,另一个由赛尔夫研究和回答的问题

    事实证明,正如我在问题中提出的理论,mp4文件直到最后才完全写入。在磁盘直接写入文件的过程中,制作人会返回到视频的开头,并更新指向各种原子的所有指针。也就是说,mp4的总体结构是ftyp->mdat->moov。其中moov包含关于所包含轨迹的所有元。不幸的是,它写在最后。但是,其位置位于标题中。这就是为什么需要seek:mdat的长度是可变的(因为它包含原始编码的帧,可以有x个)。因此,moov原子被mdat的长度抵消。当producer完成文件写入时,它将使用moov的正确位置更新头文件

    其他参考资料:

    如果采用这种方法,则最终文件必须“固定”

    在指定链接的评论部分,有一个关于修复文件的有用建议:

    为了帮助那些有问题的人,SDK似乎试图插入mdat atom的大小值,以及moov头。 我在本例中设置编码器以生成一个三个GPP文件。 为了播放输出三个GPP,您需要首先在mdat atom之前的前28个字节中创建头文件(应该都是零)。 00 00 18 66 74 79 70 33 67 70 34 00 03 00 33 67 70 34 33 67 70 36 00 02 F1 4D 6D 6D是mdat原子中的“m”第一个字节。需要修改的四个字节,以包含包含输出moov atom的流中字节的整数值(停止录制时应输出)。只要这个标题设置正确,玩家就可以找到moovatom——所有的东西都应该正确播放。 另外,这里的套接字方法也不是很灵活——您可以通过向网络提供本地套接字,然后连接到该本地套接字并处理其数据流,对网络中的数据包数据执行更精细的更改(我目前正在尝试进行实时流式传输)