I have an array of raw H264 AVPackets which get from IP Camera's RTSP.
so I'm going to put them into MP4 container (not to the file into the buffer) then stream the buffer on the network.
I read example on ffmpeg site and surfe alot on Stackoverflow so write the following code but finally when I write the mp4 result from the bufer to the file, it's not playable. event I write the buufer inside the loop it can not be played and seems there's empty packet inside the buffer.
however when I use avio_open2
and write to the file with libav it works fine and the file is playable.
#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;
}
after one week I find that it's a normal behavior of mp4 container.
actually mp4 is very fit for VOD
oroffline playback
, and not a sutible option for live streaming. Althogh mp4
container has higher compression ratio and use less B/W
, mp4 muxer
needs all AVPacket
to generate meta information
, so LibAVFormat
wait to call av_write_trailer
,means there's no video frame and write meta tags
, to put header/footer segment
. that's why seekable
memory is essential for mp4 muxer
.
I suggest to useHLS
or DASH
to send live streaming packet over the network.