C++ LibAV 将原始 H264 复用到 MP4 容器中并保留在缓冲区中

C++ LibAV muxing raw H264 into MP4 container and keeping on the buffer

提问人:Ehsan Vahab 提问时间:9/20/2023 最后编辑:Ehsan Vahab 更新时间:9/21/2023 访问量:40

问:

我有一组原始的 H264 AVPackets,它们来自 IP Camera 的 RTSP。 所以我要把它们放到 MP4 容器中(而不是文件放到缓冲区中),然后在网络上流式传输缓冲区。 我在 ffmpeg 网站上阅读了示例并在 Stackoverflow 上冲浪了很多,所以编写以下代码,但最后当我将 mp4 结果从 bufer 写入文件时,它无法播放。事件:我在循环中写入 buufer,它无法播放,并且缓冲区内似乎有空包。 但是,当我使用 libav 使用和写入文件时,它工作正常并且文件可以播放。avio_open2

#include <iostream>
#include <vector>
#include <queue>
#include "stdlib.h"
#include <fstream>
#include <list>    

extern "C" {
  #include <libavformat/avformat.h>
  #include <libavcodec/avcodec.h>
  #include <libavutil/avutil.h>
  #include <libavutil/pixdesc.h>
  #include <libswscale/swscale.h>
  #include "libavutil/imgutils.h"
  #include <libavutil/opt.h>
  #include <libavutil/mathematics.h>

}

#define VIDEO_CODEC_ID AV_CODEC_ID_H264
#define AUDIO_CODEC_ID AV_CODEC_ID_AAC
#define BUFFER_SIZE 1024*1024*10 // 10 MB buffer size (adjust as needed)


#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/img_hash.hpp>
#include "opencv2/imgproc/imgproc.hpp"
#include <pthread.h>
#include <assert.h>
#include <algorithm>
#include <limits>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>

#include <bitset>

using namespace std;
using namespace cv;

int main(int argc, char ** argv) {
    
    av_register_all();
    avcodec_register_all();
    
    FILE *fp;
    fp = fopen("./sample_iocontext.mp4", "wb");

    // Muxer2
    AVFormatContext* muxer2 = avformat_alloc_context();
    muxer2->oformat = av_guess_format("mp4", NULL, NULL);
    AVStream* video_track2 = avformat_new_stream(muxer2, NULL);

    //Muxer2
    avcodec_parameters_from_context(video_track2->codecpar, mycodec); //sample codec from another function
    video_track2->codecpar->codec_type = AVMEDIA_TYPE_VIDEO;
    video_track2->codec->codec_id = AV_CODEC_ID_H264;
    video_track2->codec->codec_type = AVMEDIA_TYPE_VIDEO;
    video_track2->codec->width = 1280;
    video_track2->codec->height = 960;
    video_track2->codec->time_base.den = 20;
    video_track2->codec->time_base.num = 1;
    video_track2->time_base = (AVRational) {1,20};
    video_track2->avg_frame_rate = mycodec->framerate;
    
    muxer2->oformat->video_codec = AV_CODEC_ID_H264;

    avio_buffer = (uint8_t*)av_malloc(BUFFER_SIZE);
    AVIOContext* ioContext = avio_alloc_context(avio_buffer, BUFFER_SIZE, 1, nullptr, nullptr, nullptr, nullptr);
    ioContext->seekable = 1;

    muxer2->pb = ioContext;
    muxer2->flags =  AVFMT_FLAG_CUSTOM_IO;
    
    // Write MP4 container header to memory buffer
    AVDictionary *options = NULL;
    av_dict_set(&options, "live", "1", 0);
    avformat_write_header(muxer2, &options);

    int packetId=0;
    for(int ii=0;ii<100;ii++){

        AVPacket *temp_packet2; //get packet from my array of AVPacket 

        AVRational encoder_time_base =  (AVRational) {1, 20};   
        temp_packet2->stream_index = video_track2->index;
        
        int64_t scaled_pts2 = av_rescale_q(packetId, encoder_time_base, video_track2->time_base);
        temp_packet2->pts = scaled_pts2;
        int64_t scaled_dts2 = av_rescale_q(packetId, encoder_time_base, video_track2->time_base);
        temp_packet2->dts = scaled_dts2;
        
        packetId++;
        av_interleaved_write_frame(muxer2, temp_packet2);

        av_packet_free(&temp_packet2);
    }
    // Write MP4 container trailer to memory buffer
    av_write_trailer(muxer2);
    fwrite(avio_buffer, 1, ioContext->pos, fp);
    fclose(fp);
    av_freep(&avio_buffer);
    avformat_free_context(muxer2);

    return 0;

}
C++ libav 大猩猩

评论

0赞 Ehsan Vahab 9/20/2023
我做了一些测试,发现av_interleaved_write_frame似乎没有立即将 mp4 数据写入缓冲区,直到调用av_write_trailer。但问题仍然存在。

答:

1赞 Ehsan Vahab 9/21/2023 #1

一周后,我发现这是 mp4 容器的正常行为。 实际上,MP4 非常适合 OR,而不是直播的可靠选择。Althogh 容器具有更高的压缩比和更少的使用,需要全部生成,所以等待调用,意味着没有视频帧和写入,要把。这就是为什么内存对于 . 我建议使用或通过网络发送实时流数据包。VODoffline playbackmp4B/Wmp4 muxerAVPacketmeta informationLibAVFormatav_write_trailermeta tagsheader/footer segmentseekablemp4 muxerHLSDASH