Extracting the h264 part of a video file (demuxing) - c++

I am trying to demux a video file into the video part (h264, mpeg4, h265, vp8, etc) and the audio part (mp3, aac, ac3, etc) and the subtitle part (srt) using ffmpeg in c++.
The audio part came out alright and played on all the media players I have, so also did the subtitle part. The video part however came out WITHOUT error and saved into a .h264 file but when I use ffprobe to check it or ffplay to play it, it always give the error "Invalid data found when processing input".
The code below
/* Separate a media file into audio, video and subtitle files (demuxing, complex) */
//TODO: mute error when subtitle is not present
#define __STDC_CONSTANT_MACROS
extern "C"
{
#include "libavformat/avformat.h"
}
int main()
{
//Input AVFormatContext and Output AVFormatContext
AVOutputFormat *ofmt_a = NULL, *ofmt_v = NULL, *ofmt_s = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx_a = NULL, *ofmt_ctx_v = NULL, *ofmt_ctx_s = NULL;
AVPacket pkt;
int ret, i;
int videoindex=-1, audioindex=-1, srtindex=-1;
int frame_index=0;
//Input file URL
const char *in_filename = "sample.mp4";
//Output file URL
const char *out_filename_v = "sample.h264";
const char *out_filename_a = "sample.mp3";
const char *out_filename_s = "sample.srt";
av_register_all();
//Input
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
printf( "Could not open input file.");
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
printf( "Failed to retrieve input stream information");
goto end;
}
//Output
avformat_alloc_output_context2(&ofmt_ctx_v, NULL, NULL, out_filename_v);
if (!ofmt_ctx_v) {
printf( "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt_v = ofmt_ctx_v->oformat;
avformat_alloc_output_context2(&ofmt_ctx_a, NULL, NULL, out_filename_a);
if (!ofmt_ctx_a) {
printf( "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt_a = ofmt_ctx_a->oformat;
avformat_alloc_output_context2(&ofmt_ctx_s, NULL, NULL, out_filename_s);
if (!ofmt_ctx_a) {
printf( "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ofmt_s = ofmt_ctx_s->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
//Create output AVStream according to input AVStream
AVFormatContext *ofmt_ctx;
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = NULL;
if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_VIDEO){
videoindex=i;
out_stream=avformat_new_stream(ofmt_ctx_v, in_stream->codec->codec);
ofmt_ctx=ofmt_ctx_v;
}
else if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO){
audioindex=i;
out_stream=avformat_new_stream(ofmt_ctx_a, in_stream->codec->codec);
ofmt_ctx=ofmt_ctx_a;
}
else if(ifmt_ctx->streams[i]->codec->codec_type==AVMEDIA_TYPE_SUBTITLE){
srtindex=i;
out_stream=avformat_new_stream(ofmt_ctx_s, in_stream->codec->codec);
ofmt_ctx=ofmt_ctx_s;
}
else{
break;
}
if (!out_stream) {
printf( "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
//Copy the settings of AVCodecContext
if (avcodec_copy_context(out_stream->codec, in_stream->codec) < 0) {
printf( "Failed to copy context from input to output stream codec context\n");
goto end;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
}
//Dump Format------------------
printf("\n==============Input Video=============\n");
av_dump_format(ifmt_ctx, 0, in_filename, 0);
printf("\n==============Output Video============\n");
av_dump_format(ofmt_ctx_v, 0, out_filename_v, 1);
printf("\n==============Output Audio============\n");
av_dump_format(ofmt_ctx_a, 0, out_filename_a, 1);
/*printf("\n==============Output Subtitle============\n");
av_dump_format(ofmt_ctx_s, 0, out_filename_s, 1);*/
printf("\n======================================\n");
//Open output file
if (!(ofmt_v->flags & AVFMT_NOFILE)) {
if (avio_open(&ofmt_ctx_v->pb, out_filename_v, AVIO_FLAG_WRITE) < 0) {
printf( "Could not open output file '%s'", out_filename_v);
goto end;
}
}
if (!(ofmt_a->flags & AVFMT_NOFILE)) {
if (avio_open(&ofmt_ctx_a->pb, out_filename_a, AVIO_FLAG_WRITE) < 0) {
printf( "Could not open output file '%s'", out_filename_a);
goto end;
}
}
if (!(ofmt_a->flags & AVFMT_NOFILE)) {
if (avio_open(&ofmt_ctx_s->pb, out_filename_s, AVIO_FLAG_WRITE) < 0) {
printf( "Could not open output file '%s'", out_filename_s);
goto end;
}
}
//Write file header
if (avformat_write_header(ofmt_ctx_v, NULL) < 0) {
printf( "Error occurred when opening video output file\n");
goto end;
}
system("pause");
if (avformat_write_header(ofmt_ctx_a, NULL) < 0) {
printf( "Error occurred when opening audio output file\n");
goto end;
}
if (avformat_write_header(ofmt_ctx_s, NULL) < 0) {
printf( "Error occurred when opening audio output file\n");
goto end;
}
AVBitStreamFilterContext* h264bsfc = av_bitstream_filter_init("h264_mp4toannexb");
while (1) {
AVFormatContext *ofmt_ctx;
AVStream *in_stream, *out_stream;
//Get an AVPacket
if (av_read_frame(ifmt_ctx, &pkt) < 0)
break;
in_stream = ifmt_ctx->streams[pkt.stream_index];
if(pkt.stream_index==videoindex){
out_stream = ofmt_ctx_v->streams[0];
ofmt_ctx=ofmt_ctx_v;
printf("Write Video Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
av_bitstream_filter_filter(h264bsfc, in_stream->codec, NULL, &pkt.data, &pkt.size, pkt.data, pkt.size, 0);
}else if(pkt.stream_index==audioindex){
out_stream = ofmt_ctx_a->streams[0];
ofmt_ctx=ofmt_ctx_a;
printf("Write Audio Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
}
else if(pkt.stream_index==srtindex){
out_stream = ofmt_ctx_s->streams[0];
ofmt_ctx=ofmt_ctx_s;
printf("Write Subtitle Packet. size:%d\tpts:%lld\n",pkt.size,pkt.pts);
}
else{
continue;
}
//Convert PTS/DTS
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
pkt.stream_index=0;
//Write
if (av_interleaved_write_frame(ofmt_ctx, &pkt) < 0) {
printf( "Error muxing packet\n");
break;
}
//printf("Write %8d frames to output file\n",frame_index);
av_free_packet(&pkt);
frame_index++;
}
av_bitstream_filter_close(h264bsfc);
//Write file trailer
av_write_trailer(ofmt_ctx_a);
av_write_trailer(ofmt_ctx_v);
av_write_trailer(ofmt_ctx_s);
end:
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx_a && !(ofmt_a->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx_a->pb);
if (ofmt_ctx_v && !(ofmt_v->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx_v->pb);
if (ofmt_ctx_s && !(ofmt_s->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx_s->pb);
avformat_free_context(ofmt_ctx_a);
avformat_free_context(ofmt_ctx_v);
avformat_free_context(ofmt_ctx_s);
system("pause");
if (ret < 0 && ret != AVERROR_EOF) {
printf( "Error occurred.\n");
return -1;
}
return 0;
}
EDIT 1
Screen shot of resultant h264 file
EDIT 2
I think the "error" has to do with FFMPEG's "Using AVStream.codec.time_base as a timebase hint to the muxer is deprecated. Set AVStream.time_base instead" error.
I revert to an older version of FFMPEG and with the same code, the resultant h264 file was ok!

You need to convert an H.264 bitstream from length prefixed mode to start code prefixed mode.This is required by some streaming formats, typically the MPEG-2 transport stream format ("mpegts").
Take a look at https://www.ffmpeg.org/ffmpeg-bitstream-filters.html#h264_005fmp4toannexb
Look at lines from 402 to 424 and from 842 to 843.
https://www.ffmpeg.org/doxygen/0.7/crystalhd_8c-source.html
I used it, to extract h264 from mp4.
//Use this filter on your first h264 input AVPacket
AVFormatContext *ifmt_ctx = NULL;
//...
//... //init input
//...
AVPacket *firstPacket;
//...
//... //get packet from stream
//...
uint8_t *dummy_p;
int dummy_int;
AVBitStreamFilterContext *filter = v_bitstream_filter_init("h264_mp4toannexb");
if (!filter)
{
printf("Can't open filter\n");
exit(1);
}
ret = av_bitstream_filter_filter(filter, ifmt_ctx->streams[videoindex]->codec, NULL,
&dummy_p, &dummy_int,
firstPacket->data, firstPacket->size, 0);
if( ret < 0 )
{
printf("Can't filter\n");
exit(1);
}
// use dummy_p to write to file, as first packet

Related

How to cut videos/audios using FFmpeg C APIs

I'm trying to write a function to cut videos/audios FFmpeg C APIs in C++. I started with the remuxing.c example from FFmpeg GitHub repository, and tried to apply the same changes mentioned in this question, but I'm getting blank screen in the beginning of the output equal to the duration that I want to cut. This is the function I came with (Differences between the function and the remuxing example noted with // <- HERE):
int cut_video(const char *in_filename, const char *out_filename, double from_seconds, double end_seconds) {
const AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket *pkt = NULL;
int ret, i;
int stream_index = 0;
int *stream_mapping = NULL;
int stream_mapping_size = 0;
pkt = av_packet_alloc();
if (!pkt) {
fprintf(stderr, "Could not allocate AVPacket\n");
return 1;
}
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
fprintf(stderr, "Could not open input file '%s'", in_filename);
goto end;
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information");
goto end;
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
ret = av_seek_frame(ifmt_ctx, -1, from_seconds * AV_TIME_BASE, AVSEEK_FLAG_ANY); // <- HERE
if (ret < 0) { // <- HERE
fprintf(stderr, "Error seek\n"); // <- HERE
goto end; // <- HERE
} // <- HERE
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
stream_mapping_size = ifmt_ctx->nb_streams;
stream_mapping = (int *)av_calloc(stream_mapping_size, sizeof(*stream_mapping));
if (!stream_mapping) {
ret = AVERROR(ENOMEM);
goto end;
}
ofmt = ofmt_ctx->oformat;
for (i = 0; i < ifmt_ctx->nb_streams; i++) {
AVStream *out_stream;
AVStream *in_stream = ifmt_ctx->streams[i];
AVCodecParameters *in_codecpar = in_stream->codecpar;
if (in_codecpar->codec_type != AVMEDIA_TYPE_AUDIO && in_codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
in_codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
stream_mapping[i] = -1;
continue;
}
stream_mapping[i] = stream_index++;
out_stream = avformat_new_stream(ofmt_ctx, NULL);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ret = avcodec_parameters_copy(out_stream->codecpar, in_codecpar);
if (ret < 0) {
fprintf(stderr, "Failed to copy codec parameters\n");
goto end;
}
out_stream->codecpar->codec_tag = 0;
}
av_dump_format(ofmt_ctx, 0, out_filename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", out_filename);
goto end;
}
}
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
goto end;
}
while (1) {
AVStream *in_stream, *out_stream;
ret = av_read_frame(ifmt_ctx, pkt);
if (ret < 0) break;
in_stream = ifmt_ctx->streams[pkt->stream_index];
if (pkt->stream_index >= stream_mapping_size || stream_mapping[pkt->stream_index] < 0 ||
av_q2d(in_stream->time_base) * pkt->pts > end_seconds) { // <- HERE
av_packet_unref(pkt);
continue;
}
pkt->stream_index = stream_mapping[pkt->stream_index];
out_stream = ofmt_ctx->streams[pkt->stream_index];
log_packet(ifmt_ctx, pkt, "in");
/* copy packet */
av_packet_rescale_ts(pkt, in_stream->time_base, out_stream->time_base);
pkt->pos = -1;
log_packet(ofmt_ctx, pkt, "out");
ret = av_interleaved_write_frame(ofmt_ctx, pkt);
/* pkt is now blank (av_interleaved_write_frame() takes ownership of
* its contents and resets pkt), so that no unreferencing is necessary.
* This would be different if one used av_write_frame(). */
if (ret < 0) {
fprintf(stderr, "Error muxing packet\n");
break;
}
}
av_write_trailer(ofmt_ctx);
end:
av_packet_free(&pkt);
avformat_close_input(&ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE)) avio_closep(&ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
av_freep(&stream_mapping);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred: %s\n", av_err2str(ret));
return 1;
}
return 0;
}
And here is how I call it:
cut_video("/Users/aliosm/Desktop/1.mp4", "/Users/aliosm/Desktop/2.mp4", 10, 40);
I searched a lot on Google and I didn't find anything useful related to this specific use-case, do you have any idea?
Finally, I was able to do that by the help from #ffmpeg channel community on Libera.Chat IRC. The final code:
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavutil/avutil.h>
#include <libavutil/timestamp.h>
}
/**
* #brief Print the information of the passed packet.
*
* #fn logPacket
* #param avFormatContext AVFormatContext of the given packet.
* #param avPacket AVPacket to log.
* #param tag String to tag the log output.
*/
void logPacket(const AVFormatContext *avFormatContext, const AVPacket *avPacket, const QString tag) {
AVRational *timeBase = &avFormatContext->streams[avPacket->stream_index]->time_base;
qDebug() << QString("%1: pts:%2 pts_time:%3 dts:%4 dts_time:%5 duration:%6 duration_time:%7 stream_index:%8")
.arg(tag)
.arg(av_ts2str(avPacket->pts))
.arg(av_ts2timestr(avPacket->pts, timeBase))
.arg(av_ts2str(avPacket->dts))
.arg(av_ts2timestr(avPacket->dts, timeBase))
.arg(av_ts2str(avPacket->duration))
.arg(av_ts2timestr(avPacket->duration, timeBase))
.arg(avPacket->stream_index);
}
/**
* #brief Cut a file in the given input file path based on the start and end seconds, and output the cutted file to the
* given output file path.
*
* #fn cutFile
* #param inputFilePath Input file path to be cutted.
* #param startSeconds Cutting start time in seconds.
* #param endSeconds Cutting end time in seconds.
* #param outputFilePath Output file path to write the new cutted file.
*
* #details This function will take an input file path and cut it based on the given start and end seconds. The cutted
* file will then be outputted to the given output file path.
*
* #return True if the cutting operation finished successfully, false otherwise.
*/
bool cutFile(const QString& inputFilePath, const long long& startSeconds, const long long& endSeconds,
const QString& outputFilePath) {
int operationResult;
AVPacket* avPacket = NULL;
AVFormatContext* avInputFormatContext = NULL;
AVFormatContext* avOutputFormatContext = NULL;
avPacket = av_packet_alloc();
if (!avPacket) {
qCritical("Failed to allocate AVPacket.");
return false;
}
try {
operationResult = avformat_open_input(&avInputFormatContext, inputFilePath.toStdString().c_str(), 0, 0);
if (operationResult < 0) {
throw std::runtime_error(QString("Failed to open the input file '%1'.").arg(inputFilePath).toStdString().c_str());
}
operationResult = avformat_find_stream_info(avInputFormatContext, 0);
if (operationResult < 0) {
throw std::runtime_error(QString("Failed to retrieve the input stream information.").toStdString().c_str());
}
avformat_alloc_output_context2(&avOutputFormatContext, NULL, NULL, outputFilePath.toStdString().c_str());
if (!avOutputFormatContext) {
operationResult = AVERROR_UNKNOWN;
throw std::runtime_error(QString("Failed to create the output context.").toStdString().c_str());
}
int streamIndex = 0;
int streamMapping[avInputFormatContext->nb_streams];
int streamRescaledStartSeconds[avInputFormatContext->nb_streams];
int streamRescaledEndSeconds[avInputFormatContext->nb_streams];
// Copy streams from the input file to the output file.
for (int i = 0; i < avInputFormatContext->nb_streams; i++) {
AVStream* outStream;
AVStream* inStream = avInputFormatContext->streams[i];
streamRescaledStartSeconds[i] = av_rescale_q(startSeconds * AV_TIME_BASE, AV_TIME_BASE_Q, inStream->time_base);
streamRescaledEndSeconds[i] = av_rescale_q(endSeconds * AV_TIME_BASE, AV_TIME_BASE_Q, inStream->time_base);
if (inStream->codecpar->codec_type != AVMEDIA_TYPE_AUDIO &&
inStream->codecpar->codec_type != AVMEDIA_TYPE_VIDEO &&
inStream->codecpar->codec_type != AVMEDIA_TYPE_SUBTITLE) {
streamMapping[i] = -1;
continue;
}
streamMapping[i] = streamIndex++;
outStream = avformat_new_stream(avOutputFormatContext, NULL);
if (!outStream) {
operationResult = AVERROR_UNKNOWN;
throw std::runtime_error(QString("Failed to allocate the output stream.").toStdString().c_str());
}
operationResult = avcodec_parameters_copy(outStream->codecpar, inStream->codecpar);
if (operationResult < 0) {
throw std::runtime_error(
QString("Failed to copy codec parameters from input stream to output stream.").toStdString().c_str());
}
outStream->codecpar->codec_tag = 0;
}
if (!(avOutputFormatContext->oformat->flags & AVFMT_NOFILE)) {
operationResult = avio_open(&avOutputFormatContext->pb, outputFilePath.toStdString().c_str(), AVIO_FLAG_WRITE);
if (operationResult < 0) {
throw std::runtime_error(
QString("Failed to open the output file '%1'.").arg(outputFilePath).toStdString().c_str());
}
}
operationResult = avformat_write_header(avOutputFormatContext, NULL);
if (operationResult < 0) {
throw std::runtime_error(QString("Error occurred when opening output file.").toStdString().c_str());
}
operationResult = avformat_seek_file(avInputFormatContext, -1, INT64_MIN, startSeconds * AV_TIME_BASE,
startSeconds * AV_TIME_BASE, 0);
if (operationResult < 0) {
throw std::runtime_error(
QString("Failed to seek the input file to the targeted start position.").toStdString().c_str());
}
while (true) {
operationResult = av_read_frame(avInputFormatContext, avPacket);
if (operationResult < 0) break;
// Skip packets from unknown streams and packets after the end cut position.
if (avPacket->stream_index >= avInputFormatContext->nb_streams || streamMapping[avPacket->stream_index] < 0 ||
avPacket->pts > streamRescaledEndSeconds[avPacket->stream_index]) {
av_packet_unref(avPacket);
continue;
}
avPacket->stream_index = streamMapping[avPacket->stream_index];
logPacket(avInputFormatContext, avPacket, "in");
// Shift the packet to its new position by subtracting the rescaled start seconds.
avPacket->pts -= streamRescaledStartSeconds[avPacket->stream_index];
avPacket->dts -= streamRescaledStartSeconds[avPacket->stream_index];
av_packet_rescale_ts(avPacket, avInputFormatContext->streams[avPacket->stream_index]->time_base,
avOutputFormatContext->streams[avPacket->stream_index]->time_base);
avPacket->pos = -1;
logPacket(avOutputFormatContext, avPacket, "out");
operationResult = av_interleaved_write_frame(avOutputFormatContext, avPacket);
if (operationResult < 0) {
throw std::runtime_error(QString("Failed to mux the packet.").toStdString().c_str());
}
}
av_write_trailer(avOutputFormatContext);
} catch (std::runtime_error e) {
qCritical("%s", e.what());
}
av_packet_free(&avPacket);
avformat_close_input(&avInputFormatContext);
if (avOutputFormatContext && !(avOutputFormatContext->oformat->flags & AVFMT_NOFILE))
avio_closep(&avOutputFormatContext->pb);
avformat_free_context(avOutputFormatContext);
if (operationResult < 0 && operationResult != AVERROR_EOF) {
qCritical("%s", QString("Error occurred: %1.").arg(av_err2str(operationResult)).toStdString().c_str());
return false;
}
return true;
}
The code is written in C++, and it is using some Qt related classes, you can remove them and use the code on plain C++ projects.
I tried my best to make it readable, I hope it is good and helpful.
Update 1: I updated the code to fix a bug in it.
Update 2: I updated the code to do some refactoring.

FFMPEG C++ Non monotonically increasing dts to muxer

I have two inputs:
Stream with audio and video
Stream with only video
I want to generate an ouput stream mixing Audio from the first stream and Video from the second stream.
But when i generate the output it says i am non monotonically increasing dts to muxer. I think im messing up with the dts.
Please help!!
Here is my code:
#include <iostream>
//Linux...
#ifdef __cplusplus
extern "C"
{
#endif
#include <libavformat/avformat.h>
#include <libavutil/mathematics.h>
#include <libavutil/time.h>
#ifdef __cplusplus
}
#endif
using namespace std;
int main(int argc, char* argv[])
{
AVOutputFormat* ofmt = NULL;
//Input AVFormatContext and Output AVFormatContext
AVFormatContext *audio_video_ifmt_ctx = NULL,
* only_video_ifmt_ctx = NULL,
* ofmt_ctx = NULL;
AVPacket audio_video_pkt, only_video_pkt;
const char *audio_video_in_filename, * only_video_in_filename, * out_filename;
int ret, i;
int audio_video_audioindex = -1;
int audio_video_videoindex = -1;
int only_video_videoindex = -1;
int audio_video_dataindex = -1;
int only_video_dataindex = -1;
int audio_video_frame_index = 0, only_video_frame_index = 0;
audio_video_in_filename = "rtmp://localhost/live/STREAM_NAME.flv";
only_video_in_filename = "rtmp://localhost/live/STREAM_NAME2.flv";
out_filename = "rtmp://localhost/live/STREAM_NAME3.flv";
//Network
avformat_network_init();
//Input ONLY VIDEO
if ((ret = avformat_open_input(&only_video_ifmt_ctx, only_video_in_filename, 0, 0)) < 0) {
printf("Could not open audio and video input file.");
return 0;
}
if ((ret = avformat_find_stream_info(only_video_ifmt_ctx, 0)) < 0) {
printf("Failed to retrieve audio and video input stream information");
return 0;
}
//Input AUDIO AND VIDEO
if ((ret = avformat_open_input(&audio_video_ifmt_ctx, audio_video_in_filename, 0, 0)) < 0) {
printf("Could not open only video input file.");
return 0;
}
if ((ret = avformat_find_stream_info(audio_video_ifmt_ctx, 0)) < 0) {
printf("Failed to retrieve only video input stream information");
return 0;
}
//Search audio_video stream index
for (i = 0; i < audio_video_ifmt_ctx->nb_streams; i++) {
if (audio_video_ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
audio_video_videoindex = i;
}
if (audio_video_ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
audio_video_audioindex = i;
}
if (audio_video_ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
audio_video_dataindex = i;
}
}
//Search only_video stream index
for (i = 0; i < only_video_ifmt_ctx->nb_streams; i++) {
if (only_video_ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
only_video_videoindex = i;
}
else if(audio_video_ifmt_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_DATA) {
only_video_dataindex = i;
}
}
av_dump_format(audio_video_ifmt_ctx, 0, audio_video_in_filename, 0);
av_dump_format(only_video_ifmt_ctx, 0, only_video_in_filename, 0);
//Allocate output stream context
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename); //RTMP
if (!ofmt_ctx) {
printf("Could not create output context\n");
ret = AVERROR_UNKNOWN;
return 0;
}
ofmt = ofmt_ctx->oformat;
//Create Output Data and Audio Stream
for (i = 0; i < audio_video_ifmt_ctx->nb_streams; i++) {
AVStream* video_in_stream;
//Create output AVStream according to input AVStream
if (i == audio_video_dataindex) {
video_in_stream = audio_video_ifmt_ctx->streams[audio_video_dataindex];
}
else if (i == audio_video_audioindex) {
video_in_stream = audio_video_ifmt_ctx->streams[audio_video_audioindex];
}
else {
video_in_stream = NULL;
continue;
}
//AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
AVCodec* codec = avcodec_find_decoder(video_in_stream->codecpar->codec_id);
AVStream* out_stream = avformat_new_stream(ofmt_ctx, codec);
if (!out_stream) {
printf("Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
return 0;
}
AVCodecContext* p_codec_ctx = avcodec_alloc_context3(codec);
ret = avcodec_parameters_to_context(p_codec_ctx, video_in_stream->codecpar);
//Copy the settings of AVCodecContext
if (ret < 0) {
printf("Failed to copy context from input to output stream codec context\n");
return 0;
}
p_codec_ctx->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
p_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_parameters_from_context(out_stream->codecpar, p_codec_ctx);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "eno:[%d] error to paramters codec paramter \n", ret);
}
}
//Create Output Video Stream
for (i = 0; i < only_video_ifmt_ctx->nb_streams; i++) {
AVStream* video_in_stream;
//Create output AVStream according to input AVStream
if (i == only_video_dataindex) {
continue;
video_in_stream = only_video_ifmt_ctx->streams[only_video_dataindex];
}
else if (i == only_video_videoindex) {
video_in_stream = only_video_ifmt_ctx->streams[only_video_videoindex];
}
else {
video_in_stream = NULL;
continue;
}
//AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
AVCodec* codec = avcodec_find_decoder(video_in_stream->codecpar->codec_id);
AVStream* out_stream = avformat_new_stream(ofmt_ctx, codec);
if (!out_stream) {
printf("Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
return 0;
}
AVCodecContext* p_codec_ctx = avcodec_alloc_context3(codec);
ret = avcodec_parameters_to_context(p_codec_ctx, video_in_stream->codecpar);
//Copy the settings of AVCodecContext
if (ret < 0) {
printf("Failed to copy context from input to output stream codec context\n");
return 0;
}
p_codec_ctx->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
p_codec_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
ret = avcodec_parameters_from_context(out_stream->codecpar, p_codec_ctx);
if (ret < 0) {
av_log(NULL, AV_LOG_ERROR, "eno:[%d] error to paramters codec paramter \n", ret);
}
}
//Dump Format------------------
av_dump_format(ofmt_ctx, 0, out_filename, 1);
//Open output URL
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0) {
printf("Could not open output URL '%s'", out_filename);
goto end;
}
}
//Write output file header
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
printf("Error occurred when opening output URL\n");
goto end;
}
//Pull stream
while (1)
{
AVStream *audio_video_in_stream, * only_video_in_stream, * out_stream;
ret = av_read_frame(audio_video_ifmt_ctx, &audio_video_pkt);
ret = av_read_frame(only_video_ifmt_ctx, &only_video_pkt);
if (ret < 0)
break;
audio_video_in_stream = audio_video_ifmt_ctx->streams[audio_video_pkt.stream_index];
only_video_in_stream = only_video_ifmt_ctx->streams[only_video_pkt.stream_index];
out_stream = NULL;
///// TREAT AUDIO PACKETS /////
if (audio_video_pkt.stream_index == audio_video_dataindex) {
out_stream = ofmt_ctx->streams[0];
}
if (audio_video_pkt.stream_index == audio_video_audioindex) {
out_stream = ofmt_ctx->streams[1];
}
//Convert PTS/DTS
if (out_stream != NULL) {
audio_video_pkt.pts = av_rescale_q_rnd(audio_video_pkt.pts, audio_video_in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
audio_video_pkt.dts = av_rescale_q_rnd(audio_video_pkt.dts, audio_video_in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
audio_video_pkt.duration = av_rescale_q(audio_video_pkt.duration, audio_video_in_stream->time_base, out_stream->time_base);
audio_video_pkt.pos = -1;
}
//Writing audio stream
if (out_stream != NULL) {
ret = av_interleaved_write_frame(ofmt_ctx, &audio_video_pkt);
}
///// TREAT VIDEO PACKETS /////
if (only_video_pkt.stream_index == only_video_videoindex) {
out_stream = ofmt_ctx->streams[2];
}
//Convert PTS/DTS
if (out_stream != NULL) {
only_video_pkt.pts = av_rescale_q_rnd(only_video_pkt.pts, only_video_in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
only_video_pkt.dts = av_rescale_q_rnd(only_video_pkt.dts, only_video_in_stream->time_base, out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
only_video_pkt.duration = av_rescale_q(only_video_pkt.duration, only_video_in_stream->time_base, out_stream->time_base);
only_video_pkt.pos = -1;
}
//Writing video
if (out_stream != NULL) {
ret = av_interleaved_write_frame(ofmt_ctx, &only_video_pkt);
}
//Desreferenciamos el paquete
av_packet_unref(&audio_video_pkt);
av_packet_unref(&only_video_pkt);
if (ret < 0) {
printf("Error muxing packet\n");
break;
}
}
//Write file trailer
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&audio_video_ifmt_ctx);
avformat_close_input(&only_video_ifmt_ctx);
/* close output */
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != AVERROR_EOF) {
printf("Error occurred.\n");
return -1;
}
return 0;
}
Here is the output:
Input #0, flv, from 'rtmp://localhost/live/STREAM_NAME.flv':
Metadata:
fileSize : 0
audiochannels : 2
2.1 : false
3.1 : false
4.0 : false
4.1 : false
5.1 : false
7.1 : false
encoder : obs-output module (libobs version 25.0.4)
Duration: 00:00:00.00, start: 2910.332000, bitrate: N/A
Stream #0:0: Data: none
Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 163 kb/s
Stream #0:2: Video: h264 (High), yuv420p(progressive), 1920x1080, 2560 kb/s, 23.98 fps, 23.98 tbr, 1k tbn, 47.95 tbc
Input #0, flv, from 'rtmp://localhost/live/STREAM_NAME2.flv':
Metadata:
encoder : Lavf58.65.101
Duration: 00:00:00.00, start: 2726.365000, bitrate: N/A
Stream #0:0: Data: none
Stream #0:1: Video: h264 (High), yuv420p(progressive), 1920x1080, 52 fps, 52 tbr, 1k tbn, 104 tbc
Output #0, flv, to 'rtmp://localhost/live/STREAM_NAME3.flv':
Stream #0:0: Data: none
Stream #0:1: Audio: aac (LC), 44100 Hz, stereo, fltp, 163 kb/s
Stream #0:2: Video: h264 (High), yuv420p(progressive), 1920x1080, q=2-31
[flv # 0000014F2CDB9500] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 2910332 >= 2726346
Error muxing packet
[flv # 0000014F2CDB9500] Failed to update header with correct duration.
[flv # 0000014F2CDB9500] Failed to update header with correct filesize.
Error occurred.

How to set start time of video saved from RTSP stream with FFMPEG

I use FFMPEG to record video from a RTSP stream. What my code does is get current day time, create a folder with this format year/month/day/hour/minute and save the video to that folder.
When a new minute arrive, I create the new folder base on the new minute and run the record again to the new folder.
Basically It works, but the next video start time is continue the end of previous video. For example:
video1: 00:00 -> 00:55
video2: 00:56 -> ...
I hope I can set for all videos start from 00:00. Can I do that?
Here my code
ffmpeg.h
class CtFfmpeg {
public:
CtFfmpeg();
~CtFfmpeg();
void init();
int getInput();
int getOutputName(const char *filename);
int release();
int ret;
AVFormatContext *ifmt_ctx, *ofmt_ctx;
AVStream *in_stream, *out_stream;
AVPacket pkt;
const char *in_filename;
char *out_filename;
private:
int setOutput(const char *outfilename);
AVOutputFormat *ofmt;
};
ffmpeg.cpp
#include "ctffmpeg.h"
CtFfmpeg::CtFfmpeg() {
in_filename = new char [1024];
out_filename = new char [1024];
}
CtFfmpeg::~CtFfmpeg() {
delete [] in_filename;
delete [] out_filename;
}
void CtFfmpeg::init() {
avcodec_register_all();
av_register_all();
avformat_network_init();
pkt = { 0 };
av_init_packet(&pkt);
ofmt = NULL;
ifmt_ctx = NULL;
ofmt_ctx = NULL;
return;
}
int CtFfmpeg::release() {
av_write_trailer(ofmt_ctx);
avcodec_close(out_stream->codec);
// avcodec_close(in_stream->codec);
// avformat_close_input(&ifmt_ctx);
/* close output */
if (!(ofmt->flags & AVFMT_NOFILE))
avio_close(ofmt_ctx->pb);
avformat_free_context(ofmt_ctx);
av_free_packet(&pkt);
if (ret < 0 && ret != AVERROR_EOF) {
fprintf(stderr, "Error occurred\n");
return 1;
}
}
int CtFfmpeg::getInput() {
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0) {
fprintf(stderr, "Could not open input file '%s'", in_filename);
release();
}
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0) {
fprintf(stderr, "Failed to retrieve input stream information");
release();
}
av_dump_format(ifmt_ctx, 0, in_filename, 0);
}
int CtFfmpeg::setOutput(const char *outfilename) {
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, outfilename);
if (!ofmt_ctx) {
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
release();
}
ofmt = ofmt_ctx->oformat;
for (int i = 0; i < ifmt_ctx->nb_streams; i++) {
in_stream = ifmt_ctx->streams[i];
out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream) {
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
release();
}
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0) {
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
release();
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
out_stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
} // for
av_dump_format(ofmt_ctx, 0, outfilename, 1);
if (!(ofmt->flags & AVFMT_NOFILE)) {
ret = avio_open(&ofmt_ctx->pb, outfilename, AVIO_FLAG_WRITE);
if (ret < 0) {
fprintf(stderr, "Could not open output file '%s'", outfilename);
release();
}
}
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0) {
fprintf(stderr, "Error occurred when opening output file\n");
release();
}
}
int CtFfmpeg::getOutputName(const char *filename){
sprintf(out_filename,filename);
setOutput(out_filename);
}
main.cpp
#include "ctfolder.h"
#include "ctffmpeg.h"
CtFfmpeg * ff;
int main(int argc, char** argv) {
if (argc < 2) {
printf("usage: %s <RTSP link> \n", argv[0]);
return 1;
}
ff = new CtFfmpeg();
ff->in_filename = argv[1]; //RTSP input link
ff->init();
ff->getInput();
string filename;
videoRecorder obj;
int start, now;
start = obj.get_current_min();
if(obj.create_folder(0755))
cout << "Cannot create folder, maybe it already exists" << endl;
else
cout << "Create folder succesfully" << endl;
int skip = 0;
while(1){
filename = obj.update_filename();
ff->getOutputName(filename.c_str());
while((now = obj.get_current_min()) == start) {
ff->ret = av_read_frame(ff->ifmt_ctx, &(ff->pkt));
skip++;
if(skip==1)
continue;
if(skip>2)
skip=2;
if (ff->ret < 0)
continue;
ff->pkt.pts = av_rescale_q_rnd(ff->pkt.pts, ff->in_stream->time_base, ff->out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
ff->pkt.dts = av_rescale_q_rnd(ff->pkt.dts, ff->in_stream->time_base, ff->out_stream->time_base, (AVRounding)(AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX));
ff->pkt.duration = av_rescale_q(ff->pkt.duration, ff->in_stream->time_base, ff->out_stream->time_base);
ff->pkt.pos = -1;
ff->ret = av_interleaved_write_frame(ff->ofmt_ctx, &(ff->pkt));
if (ff->ret < 0) {
fprintf(stderr, "Error muxing packet\n");
continue;
}
av_free_packet(&(ff->pkt));
}
ff->release();
cout << "New minute!" << endl;
if(obj.create_folder(0755))
cout << "Cannot create folder, something's wrong" << endl;
else
cout << "Create folder succesfully" << endl;
start = now;
}
return 0;
}
You need to shift your recording packet's pts to 0.
while(<some condition>)
{
//...
int64_t pts_offset = AV_NOPTS_VALUE ;
while((now = obj.get_current_min()) == start)
{
//...
ff.pkt.pts = ...
//...
if( pts_offset == AV_NOPTS_VALUE )
{
pts_offset = ff.pkt.pts ;
}
ff.pkt.pts -= pts_offset ;
// ...
}
}
I tried to build your code and add Alexander Chernin suggestion to it but I face to muxer error!
When you decrease recording packet's pts, it's value go lower than recording packet's dts. In avcodec.h, above declaration of pts I found this comment:
pts MUST be larger or equal to dts as presentation cannot happen before decompression.
I solved this error by decreasing recording packet's dts.
ff->pkt.pts = av_rescale_q_rnd(ff->pkt.pts, ff->in_stream->ff->out_stream->(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
if (pts_offset == AV_NOPTS_VALUE) {
pts_offset = ff->pkt.pts;
}
ff->pkt.pts -= pts_offset;
ff->pkt.dts -= pts_offset;
ff->pkt.dts = av_rescale_q_rnd(ff->pkt.dts, ff->in_stream->time_base,ff->out_stream->time_base,(AVRounding) (AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
ff->pkt.duration = av_rescale_q(ff->pkt.duration,ff->in_stream->time_base,ff->out_stream->time_base);
ff->pkt.pos = -1;

FFMPEG. Read frame, process it, put it to output video. Copy sound stream unchanged

I want to apply processing to a video clip with sound track, extract and process frame by frame and write result to output file. Number of frames, size of frame and speed remains unchanged in output clip. Also I want to keep the same audio track as I have in source.
I can read clip, decode frames and process then using opencv. Audio packets are also writes fine. I'm stuck on forming output video stream.
The minimal runnable code I have for now (sorry it not so short, but cant do it shorter):
extern "C" {
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include "libavcodec/avcodec.h"
#include <libavutil/opt.h>
#include <libavdevice/avdevice.h>
#include <libswscale/swscale.h>
}
#include "opencv2/opencv.hpp"
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55,28,1)
#define av_frame_alloc avcodec_alloc_frame
#endif
using namespace std;
using namespace cv;
static void log_packet(const AVFormatContext *fmt_ctx, const AVPacket *pkt, const char *tag)
{
AVRational *time_base = &fmt_ctx->streams[pkt->stream_index]->time_base;
char buf1[AV_TS_MAX_STRING_SIZE] = { 0 };
av_ts_make_string(buf1, pkt->pts);
char buf2[AV_TS_MAX_STRING_SIZE] = { 0 };
av_ts_make_string(buf1, pkt->dts);
char buf3[AV_TS_MAX_STRING_SIZE] = { 0 };
av_ts_make_string(buf1, pkt->duration);
char buf4[AV_TS_MAX_STRING_SIZE] = { 0 };
av_ts_make_time_string(buf1, pkt->pts, time_base);
char buf5[AV_TS_MAX_STRING_SIZE] = { 0 };
av_ts_make_time_string(buf1, pkt->dts, time_base);
char buf6[AV_TS_MAX_STRING_SIZE] = { 0 };
av_ts_make_time_string(buf1, pkt->duration, time_base);
printf("pts:%s pts_time:%s dts:%s dts_time:%s duration:%s duration_time:%s stream_index:%d\n",
buf1, buf4,
buf2, buf5,
buf3, buf6,
pkt->stream_index);
}
int main(int argc, char **argv)
{
AVOutputFormat *ofmt = NULL;
AVFormatContext *ifmt_ctx = NULL, *ofmt_ctx = NULL;
AVPacket pkt;
AVFrame *pFrame = NULL;
AVFrame *pFrameRGB = NULL;
int frameFinished = 0;
pFrame = av_frame_alloc();
pFrameRGB = av_frame_alloc();
const char *in_filename, *out_filename;
int ret, i;
in_filename = "../../TestClips/Audio Video Sync Test.mp4";
out_filename = "out.mp4";
// Initialize FFMPEG
av_register_all();
// Get input file format context
if ((ret = avformat_open_input(&ifmt_ctx, in_filename, 0, 0)) < 0)
{
fprintf(stderr, "Could not open input file '%s'", in_filename);
goto end;
}
// Extract streams description
if ((ret = avformat_find_stream_info(ifmt_ctx, 0)) < 0)
{
fprintf(stderr, "Failed to retrieve input stream information");
goto end;
}
// Print detailed information about the input or output format,
// such as duration, bitrate, streams, container, programs, metadata, side data, codec and time base.
av_dump_format(ifmt_ctx, 0, in_filename, 0);
// Allocate an AVFormatContext for an output format.
avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, out_filename);
if (!ofmt_ctx)
{
fprintf(stderr, "Could not create output context\n");
ret = AVERROR_UNKNOWN;
goto end;
}
// The output container format.
ofmt = ofmt_ctx->oformat;
// Allocating output streams
for (i = 0; i < ifmt_ctx->nb_streams; i++)
{
AVStream *in_stream = ifmt_ctx->streams[i];
AVStream *out_stream = avformat_new_stream(ofmt_ctx, in_stream->codec->codec);
if (!out_stream)
{
fprintf(stderr, "Failed allocating output stream\n");
ret = AVERROR_UNKNOWN;
goto end;
}
ret = avcodec_copy_context(out_stream->codec, in_stream->codec);
if (ret < 0)
{
fprintf(stderr, "Failed to copy context from input to output stream codec context\n");
goto end;
}
out_stream->codec->codec_tag = 0;
if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
{
out_stream->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
}
}
// Show output format info
av_dump_format(ofmt_ctx, 0, out_filename, 1);
// Open output file
if (!(ofmt->flags & AVFMT_NOFILE))
{
ret = avio_open(&ofmt_ctx->pb, out_filename, AVIO_FLAG_WRITE);
if (ret < 0)
{
fprintf(stderr, "Could not open output file '%s'", out_filename);
goto end;
}
}
// Write output file header
ret = avformat_write_header(ofmt_ctx, NULL);
if (ret < 0)
{
fprintf(stderr, "Error occurred when opening output file\n");
goto end;
}
// Search for input video codec info
AVCodec *in_codec = nullptr;
AVCodecContext* avctx = nullptr;
int video_stream_index = -1;
for (int i = 0; i < ifmt_ctx->nb_streams; i++)
{
if (ifmt_ctx->streams[i]->codec->coder_type == AVMEDIA_TYPE_VIDEO)
{
video_stream_index = i;
avctx = ifmt_ctx->streams[i]->codec;
in_codec = avcodec_find_decoder(avctx->codec_id);
if (!in_codec)
{
fprintf(stderr, "in codec not found\n");
exit(1);
}
break;
}
}
// Search for output video codec info
AVCodec *out_codec = nullptr;
AVCodecContext* o_avctx = nullptr;
int o_video_stream_index = -1;
for (int i = 0; i < ofmt_ctx->nb_streams; i++)
{
if (ofmt_ctx->streams[i]->codec->coder_type == AVMEDIA_TYPE_VIDEO)
{
o_video_stream_index = i;
o_avctx = ofmt_ctx->streams[i]->codec;
out_codec = avcodec_find_encoder(o_avctx->codec_id);
if (!out_codec)
{
fprintf(stderr, "out codec not found\n");
exit(1);
}
break;
}
}
// openCV pixel format
AVPixelFormat pFormat = AV_PIX_FMT_RGB24;
// Data size
int numBytes = avpicture_get_size(pFormat, avctx->width, avctx->height);
// allocate buffer
uint8_t *buffer = (uint8_t *)av_malloc(numBytes * sizeof(uint8_t));
// fill frame structure
avpicture_fill((AVPicture *)pFrameRGB, buffer, pFormat, avctx->width, avctx->height);
// frame area
int y_size = avctx->width * avctx->height;
// Open input codec
avcodec_open2(avctx, in_codec, NULL);
// Main loop
while (1)
{
AVStream *in_stream, *out_stream;
ret = av_read_frame(ifmt_ctx, &pkt);
if (ret < 0)
{
break;
}
in_stream = ifmt_ctx->streams[pkt.stream_index];
out_stream = ofmt_ctx->streams[pkt.stream_index];
log_packet(ifmt_ctx, &pkt, "in");
// copy packet
pkt.pts = av_rescale_q_rnd(pkt.pts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.dts = av_rescale_q_rnd(pkt.dts, in_stream->time_base, out_stream->time_base, AVRounding(AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX));
pkt.duration = av_rescale_q(pkt.duration, in_stream->time_base, out_stream->time_base);
pkt.pos = -1;
log_packet(ofmt_ctx, &pkt, "out");
if (pkt.stream_index == video_stream_index)
{
avcodec_decode_video2(avctx, pFrame, &frameFinished, &pkt);
if (frameFinished)
{
struct SwsContext *img_convert_ctx;
img_convert_ctx = sws_getCachedContext(NULL,
avctx->width,
avctx->height,
avctx->pix_fmt,
avctx->width,
avctx->height,
AV_PIX_FMT_BGR24,
SWS_BICUBIC,
NULL,
NULL,
NULL);
sws_scale(img_convert_ctx,
((AVPicture*)pFrame)->data,
((AVPicture*)pFrame)->linesize,
0,
avctx->height,
((AVPicture *)pFrameRGB)->data,
((AVPicture *)pFrameRGB)->linesize);
sws_freeContext(img_convert_ctx);
// Do some image processing
cv::Mat img(pFrame->height, pFrame->width, CV_8UC3, pFrameRGB->data[0],false);
cv::GaussianBlur(img,img,Size(5,5),3);
cv::imshow("Display", img);
cv::waitKey(5);
// --------------------------------
// Transform back to initial format
// --------------------------------
img_convert_ctx = sws_getCachedContext(NULL,
avctx->width,
avctx->height,
AV_PIX_FMT_BGR24,
avctx->width,
avctx->height,
avctx->pix_fmt,
SWS_BICUBIC,
NULL,
NULL,
NULL);
sws_scale(img_convert_ctx,
((AVPicture*)pFrameRGB)->data,
((AVPicture*)pFrameRGB)->linesize,
0,
avctx->height,
((AVPicture *)pFrame)->data,
((AVPicture *)pFrame)->linesize);
// --------------------------------------------
// Something must be here
// --------------------------------------------
//
// Write fideo frame (How to write frame to output stream ?)
//
// --------------------------------------------
sws_freeContext(img_convert_ctx);
}
}
else // write sound frame
{
ret = av_interleaved_write_frame(ofmt_ctx, &pkt);
}
if (ret < 0)
{
fprintf(stderr, "Error muxing packet\n");
break;
}
// Decrease packet ref counter
av_packet_unref(&pkt);
}
av_write_trailer(ofmt_ctx);
end:
avformat_close_input(&ifmt_ctx);
// close output
if (ofmt_ctx && !(ofmt->flags & AVFMT_NOFILE))
{
avio_closep(&ofmt_ctx->pb);
}
avformat_free_context(ofmt_ctx);
if (ret < 0 && ret != AVERROR_EOF)
{
char buf_err[AV_ERROR_MAX_STRING_SIZE] = { 0 };
av_make_error_string(buf_err, AV_ERROR_MAX_STRING_SIZE, ret);
fprintf(stderr, "Error occurred: %s\n", buf_err);
return 1;
}
avcodec_close(avctx);
av_free(pFrame);
av_free(pFrameRGB);
return 0;
}
Your original code segfaults in my case. Initializing the output codec context seems to fix it. The code below works for me but I didn't test the OpenCV stuff as I don't have the lib installed.
Get the codec context:
// Search for output video codec info
AVCodec *out_codec = NULL;
AVCodecContext* o_avctx = NULL;
int o_video_stream_index = -1;
for (int i = 0; i < ofmt_ctx->nb_streams; i++)
{
if (ofmt_ctx->streams[i]->codec->coder_type == AVMEDIA_TYPE_VIDEO)
{
o_video_stream_index = i;
out_codec = avcodec_find_encoder(ofmt_ctx->streams[i]->codec->codec_id);
o_avctx = avcodec_alloc_context3(out_codec);
o_avctx->height = avctx->height;
o_avctx->width = avctx->width;
o_avctx->sample_aspect_ratio = avctx->sample_aspect_ratio;
if (out_codec->pix_fmts)
o_avctx->pix_fmt = out_codec->pix_fmts[0];
else
o_avctx->pix_fmt = avctx->pix_fmt;
o_avctx->time_base = avctx->time_base;
avcodec_open2(o_avctx, out_codec, NULL);
}
}
Encode and write:
// Main loop
while (1)
{
...
if (pkt.stream_index == video_stream_index)
{
avcodec_decode_video2(avctx, pFrame, &frameFinished, &pkt);
if (frameFinished)
{
...
// --------------------------------------------
// Something must be here
// --------------------------------------------
int got_packet = 0;
AVPacket enc_pkt = { 0 };
av_init_packet(&enc_pkt);
avcodec_encode_video2(o_avctx, &enc_pkt, pFrame, &got_packet);
av_interleaved_write_frame(ofmt_ctx, &enc_pkt);
....
}
}
you should assign processed frame's packets information to your Original packets then pass it to av_interleaved_write_frame

Decoding m4a and dumping PCM data gives back noise

I'm using the code below (modified from the examples given in libavcodec) to decode audio files
int main(int argc, char **argv)
{
av_register_all();
avcodec_register_all();
char *filename = argv[1];
char *outfilename = argv[2];
FILE *outfile;
AVCodec *codec;
AVCodecContext *c= NULL;
AVPacket avpkt;
AVFrame *frame = av_frame_alloc();
printf("Decode audio file %s to %s\n", filename, outfilename);
outfile = fopen(outfilename, "wb");
if (!outfile) {
fprintf(stderr, "Could not write to %s\n", outfilename);
av_free(c);
exit(1);
}
AVFormatContext *format_context = NULL;
avformat_open_input(&format_context, filename, NULL, NULL);
printf("Opened format input\n");
int find_result = avformat_find_stream_info(format_context, NULL);
if (find_result < 0) {
fprintf(stderr, "Cannot find stream info\n");
avformat_close_input(&format_context);
exit(-1);
}
int audio_stream_idx = av_find_best_stream(format_context, AVMEDIA_TYPE_AUDIO, -1, -1, &codec, 0);
if (audio_stream_idx < 0) {
fprintf(stderr,"Couldn't find stream information\n");
exit(-1);
}
// Get a pointer to the codec context for the audio stream
c = format_context->streams[audio_stream_idx]->codec;
av_opt_set_int(c, "refcounted_frames", 1, 0);
if (avcodec_open2(c, codec, NULL) < 0) {
fprintf(stderr, "Could not open codec\n");
exit(-1);
}
// read the audio frames
int ret, got_frame;
while (1) {
if ((ret = av_read_frame(format_context, &avpkt)) < 0)
break;
if (avpkt.stream_index == audio_stream_idx) {
avcodec_get_frame_defaults(frame);
got_frame = 0;
ret = avcodec_decode_audio4(c, frame, &got_frame, &avpkt);
if (ret < 0) {
fprintf(stderr, "Error decoding audio\n");
continue;
}
if (got_frame) {
// write to disk
fwrite(frame->extended_data[0], 1, frame->linesize[0], outfile);
}
}
av_free_packet(&avpkt);
}
fclose(outfile);
printf("Finished\n");
if (c)
avcodec_close(c);
avformat_close_input(&format_context);
av_frame_free(&frame);
}
I tried .mp3 and .m4a files; .mp3 files work fine but not for .m4a files. Any help?
Most aac files are in the FLOAT format i.e. AV_SAMPLE_FMT_FLTP, while libraries such as libao are only able to play audio as integer format i.e. AV_SAMPLE_FORMAT_S16.
As a result, you'd need to use libavresample to resample the music and convert the format as appropriate.