How to generate fragmented mp4 files programmatically - c++

I have a media .h264 live streaming server, and want to mux .h264 frames to fragmented mp4 files. I am wondering does any library could support this?
As far as I know, ffmpeg.exe and Bento4 could support this, but I want to use a library to do that in my code, not executing another process.
To specify my point, I want to generate fragmented mp4 files, which could be achieved by executing ffmpeg.exe like below,
ffmpeg -i xx.h264
-vcodec copy -an -f mp4 -reset_timestamps 0
-movflags empty_moov+default_base_moof+frag_keyframe -loglevel quiet
xxx.mp4"
I want to mux mp4 files in my code, not create another process to do it.
Thanks.

More detailed:
AVDictionary* opts = NULL;
av_dict_set(&opts, "movflags", "frag_keyframe+empty_moov", 0);
and then later:
//init muxer, write output file header
avformat_write_header(formatContext, &opts);
where formatContext is pointer of AVFormatContext obtained when output file is opened using: avformat_alloc_output_context2 and avio_open functions.

Related

Record audio data to an existing media file using FFMPEG API

My task is to record the received audio data in a media file. I have no problem with this, everything works fine. But, when closing the audio file, I will no longer be able to re-open it and write the audio data to the end of the audio file. How do I solve this problem ? And in general, is it possible to write new data to the end of an existing media file ?
This is a piece of code where I record the trailer and close the media file:
// Writing the stream trailer to an output
// media file and free the file private data.
av_write_trailer(p_oFrmCtx);
avformat_close_input(&p_oFrmCtx);
As far as I know, opening an existing audio file and writing to it is not possible. What you can do is write the incoming data to a new file and merge it with the previous one (the one at the end of which you wanted to write the data). You can use below command to achieve that.
ffmpeg -i "concat:file1.mp3|file2.mp3" -acodec copy output.mp3
If you have a list of files to be merged together, run the below command
$ ffmpeg -f concat -safe 0 -i filelist.txt -c copy output.mp3
Note the list should be of following format
$ cat filelist.txt
file '/audio/001.mp3'
file '/audio/002.mp3'
file '/audio/003.mp3'
file '/audio/004.mp3'

Copying avcodec parameters

I am trying to use libav to convert an MP4 file to an MP3 file. Basically trying to achieve what ffmpeg -i filename.mp4 filename.mp3 does. I've found this official example. But when I run it with an input MP4 and an output MP3 I get an error:
Invalid audio stream. Exactly one MP3 audio stream is required.
I am not at all familiar with this library but I think I have narrowed the problem down to this line:
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
It seems to copy all streams for a video file but we only need one for the MP3 file? I am not sure. There doesn't seem to be a function to copy only the parameters relevant to audio. I checked the sources, avcodec_parameters_copy does a simple memcpy.
Questions:
Is this the actual problem?
How do I solve it?
Am I on the right track to achieve the goal of extracting audio from a video file? I've seen this question (and other similar questions like this and this) on here but none seem to have a complete code example. The C API documentation for this library is also a little lacking.
You can have multiple audio tracks in mp4 file, but only one such track in an mp3 file. The easiest fix for the remuxing example would be to replace lines 101-103:
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO ||
stream_index != 0) {
This, naturally, is relevant only if the output is mp3.
PS, make sure that your input mp4 uses the MP3 audio codec. If it does not (and most have AAC or AC3 these days), it's not enough to remux the file, you also need to decode and re-encode the audio stream.

FFmpeg API example (encode_video.c) does not work correctly

I am using the official encode_video.c example to test if FFmpeg works correctly for me.
I got the pre-built windows edition from ffmpeg.zeranoe.com/builds. It is built already with libx264 and other external libraries. I got both dev and shared editions and added the DLLs, header files and libs accordingly in Visual Studio.
Now the encode_video.c example does not work correctly.
What I tried:
I compiled the example and run it on many different file formats and codecs such as the following.
First I tried all of these file formats (.mp4, .m4v, .h264, .x264, .avi, .flv) with codec name as libx264. The code executed without errors but the output video file did not play in VLC or Windows 10 default player.
Next, I tried all of those above file formats but with codec name as mpeg4. The code executed without errors but the output video file played only for .m4v in VLC.
What is expected:
All of those combinations should have produced a video file which could be played in VLC. None of them worked except for .m4v as file format and mpeg4 as codec name.
Please tell me how to make this work for h264. I mainly want it to work for h264 as that is only important for now.
I am running the code like ./encode_video.exe test.mp4 libx264 where first argument is output filename and second argument is codec name.
This is the output for test.mp4 and libx264 as command line arguments https://imgur.com/a/AHLQwuK
It seems that in the encode function, it goes over the below code and returns because of AVERROR(EAGAIN) or AVERROR_EOF. Please tell me what is happening.
while (ret >= 0) {
ret = avcodec_receive_packet(enc_ctx, pkt);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
return;
else if (ret < 0) {
fprintf(stderr, "Error during encoding\n");
exit(1);
}
printf("Write packet %3"PRId64" (size=%5d)\n", pkt->pts, pkt->size);
fwrite(pkt->data, 1, pkt->size, outfile);
av_packet_unref(pkt);
}
I used DepenciesGUI to find out the DLLs linked and it shows that the DLLs are correctly linked. Please help me figure out what the problem is now!!
I found this question because I had the same issue (couldn't watch video generated by that example). Regarding your concern:
It seems that in the encode function, it goes over the below code and
returns because of AVERROR(EAGAIN) or AVERROR_EOF. Please tell me what
is happening.
While stepping through the code in debugger, I too noticed those occasional "errors". However, those frames are eventually processed either in subsequent loop iteration or when the encoder is flashed via:
/* flush the encoder */
encode(c, NULL, pkt, f);
I too tried to use VLC, and also QuickTime, with no luck.
Then I noticed ffplay tool in the ffmpeg's bin folder, that would play all videos produced by that example, with different codecs.
My point is - the issue might be with the viewer, not with the video file.
just change:
./encode_video.exe test.mp4 libx264
to:
./encode_video.exe test.264 libx264
and the result file "test.264" can be played by vlc player.
I'm running ffmpeg's encode_video.c demo on my Mac and Apple's QuickTime Player seems not supporting this format.
You want to use the muxing.c example instead.
The encode_video example doesn't produce an MPEG compliant file.

How to set the moov atom position when encoding video using ffmpeg in c++

I'm encoding some h264 video into a mp4 container using ffmpeg in c++. But the result videos place the moov atom(or metadata?) at the end of the video file, it's bad for internet streaming.
So how can I set the moov atom position to the front?
MOVMuxContext is an internal header and should not be accessed directly. Its implementation is not part of the API and it can change.
The official way to do it is setting options via an AVDictionary :
AVDictionary* options = nullptr;
av_dict_set( &options, "movflags", "faststart", 0 );
avio_open2(..., &options);
You need to use faststart flag of ffmpeg to place the moov atom in the beginning of the MP4 file, Here is the explanation of the flag. Programatically you need to set the flag in output context, here is the sample code and its working for me,
AVFormatContext *outFormatCtx;
// Write MOOV atom at the begining of the MP4 file
MOVMuxContext *mov = NULL;
mov = (MOVMuxContext *)outFormatCtx->priv_data;
mov->flags |= FF_MOV_FLAG_FASTSTART;

Convert video file to TIFF with ffmpeg.dll or avcodec.dll? Is "on-the-fly" possible?

I want to create a program, which gets a video-file from Qt, converts that video file to TIFF-files and sends them to an algorithm which handles these TIFF-Files.
My questions:
is it possible with ffmpeg or avcodec not to convert a video-file to TIFF-files first on harddrive and send them to the algorithm after that, but to convert frame for frame and send it to the algorithm right away?
The more important question: Is it possible to do that not with an external process with ffmpeg.exe, but with ffmpeg.dll? Or is it only possible with avcodec.dll? (It doesn't have to be "on-the-fly" like at my point above) How can I create a ffmpeg.dll with header and lib?
for exporting tif :
http://www.repaire.net/forums/cinema-numerique/215306-projet-dencodage-dcp.html
Creating a tiff from second 29 in a mpeg, using ffmpeg dd201110 can be done like this:
ffmpeg -i 'test.mpg' -vframes 1 -compression_level 0 -ss 29 'test.tiff'
YMMV :-D
If you dont want to store the image as a file, take a look at ffmpeg-php
http://ffmpeg-php.sourceforge.net/
$movie->getFrame([Integer framenumber])
Returns a frame from the movie as an ffmpeg_frame object.
$frame->toGDImage()
Returns a truecolor GD image of the frame.
There may be C code underneath you can reuse..