Cannot mux video with libav: Tag avc1 incompatible with output codec id '27' - video-processing

When I try to convert mp4 to flv, I get this error:
Tag avc1 incompatible with output codec id '27'
Codec 27 is AV_CODEC_ID_H264
I followed the examples from the documentation, and could write an image from mp4, or remux the file using the same encoders.
https://github.com/FFmpeg/FFmpeg/blob/master/doc/examples/muxing.c
AVCodec* video_codec = NULL;
// It loops through the streams and copy the parameters
for (int i=0; I<ctx->nb_streams; i++) {
if (ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {
video_codec = avcodec_find_decoder(stream->codepar->codec_id);
}
}
...
const char* output_file = "output_video.flv"
// it works with mp4, not with flv
avformat_alloc_output_context2(&fmt_ctx, NULL, "flv", output_file);
...
// Error here
avformat_write_header(fmt_ctx, NULL);
Output #0, flv, to 'output_video.flv':
Stream #0:0: Video: h264 (avc1 / 0x4), none, 1920x1080, q=2-31, 6664 kb/s
Stream #0:1: Audio: aac (mp4a / 0x5), 48000 Hz, 2 channels, 128 kb/s
[flv # 0x5] Tag avc1 incompatible with output codec id '27' ([7][0][0][0])
What does this error means and where is this tag defined? Why copying the parameters isn't enough?

Set the codec_tag (out_stream->codecpar->codec_tag) as 0 or corresponding AVI FOURCC codec tag inside the for loop for each output stream.

Related

libavcodec/libx264 isn't respecting keyint_min

Using libavcodec 57.107.100, I have some code to encode frames into H.264 and I'm working on tweaking the settings to prep resulting videos to be streamed with DASH, which requires consistent keyframe timings. So I'm setting the GOP to 4x the framerate and setting the keyint_min to the same as the GOP so that I can guarantee that the keyframe interval lines up with the 4 second segment boundaries.
I'm using the following code to build the AVCodec and AVCodecContext:
AVCodec* codec = NULL;
codec = avcodec_find_encoder_by_name("libx264");
AVCodecContext* avcodec_context = avcodec_alloc_context3(codec);
context->bit_rate = 200000;
context->height = 640;
context->width = 480;
context->keyint_min = 100;
context->gop_size = 100;
context->qmax = 31;
context->qmin = 2;
context->pix_fmt = AV_PIX_FMT_YUV420P;
context->time_base = (AVRational) {1, 25};
Clearly, the keyint_min is 100 here, yet when I execute my program, the stderr output from libavcodec says this when the encoding starts:
[libx264 # 0x5577bde61f20] using cpu capabilities: MMX2 SSE2Fast SSSE3 SSE4.2 AVX FMA3 BMI2
AVX2
[libx264 # 0x5577bde61f20] profile High, level 3.0
[libx264 # 0x5577bde61f20] 264 - core 152 r2854 e9a5903 - H.264/MPEG-4 AVC codec - Copyleft 2003-2017 - http://www.videolan.org/x264.html - options: cabac=1 ref=3 deblock=1:0:0 analyse=0x3:0x113 me=hex subme=7 psy=1 psy_rd=1.00:0.00 mixed_ref=1 me_range=16 chroma_me=1 trellis=1 8x8dct=1 cqm=0 deadzone=21,11 fast_pskip=1 chroma_qp_offset=-2 threads=12 lookahead_threads=2 sliced_threads=0 nr=0 decimate=1 interlaced=0 bluray_compat=0 constrained_intra=0 bframes=3 b_pyramid=2 b_adapt=1 b_bias=0 direct=1 weightb=1 open_gop=0 weightp=2 keyint=100 keyint_min=51 scenecut=40 intra_refresh=0 rc_lookahead=40 rc=abr mbtree=1 bitrate=200 ratetol=1.0 qcomp=0.60 qpmin=2 qpmax=31 qpstep=4 ip_ratio=1.40 aq=1:1.00
For emphasis, in the third line of that blurb, the encoder says keyint=100 keyint_min=51. So obviously my GOP is being set correctly at 100, but the keyint_min is not being respected. Since the FFMPEG docs are pretty difficult to approach, I haven't been able to find an answer to this. Does anyone know what I'm missing?
The x264 encoder will clamp keyint_min to keyint/2+1
Pass an option directly to x264 to avoid premature IDR frames
e.g.
av_opt_set(context->priv_data, "x264opts", "no-scenecut", 0);
or
context->scenechange_threshold = 0;

How to FFmpeg decode and extract metadata from last frame?

I am decoding using FFMpeg. The videos I am decoding are H.264 or MPEG4 videos using C code. I am using the 32bit libs. I have successfully decoded and extracted the metadata for the first frame. I would now like to decode the last frame. I have a defined duration of the video, and felt it was a safe assumption to say that isLastFrame = duration. Here's what I have, any suggestions?
AVFormatContext* pFormatCtx = avformat_alloc_context();
avformat_open_input(&pFormatCtx, filename, NULL, NULL);
int64_t duration = pFormatCtx->duration;
i=0;
while(av_read_frame(pFormatCtx, &packet)>=0) {
/* Is this a packet from the video stream? */
if(packet.stream_index==videoStream) {
/* Decode video frame*/
avcodec_decode_video2(pCodecCtx, pFrame, &duration, &packet);
}
Any help is much appreciated! :)
Thanks everyone for your help but I found that the reason the AV_SEEK_FRAME duration wasn't working was because you must multiply it by 1000 for it to be applicable in read frame. Also please note that the reason I have but decode_video instead of the decode functions calls is because I was using 32 bit and created my own but if you plug in video_decode() or I believe it's decode_video2 it works just as well. Hopefully this will help any fellow decoders in the future.
AVFormat Format;
int64_t duration = Format->duration;
duration = duration * 1000;
if (av_seek_frame(Format, Packet->stream_index, duration, AVSEEK_FLAG_ANY) <= 0)
{
/* read the frame and decode the packet */
if (av_read_frame(FormatContext, &Packet) >= 0)
{
/*decode the video frame*/
decode_video(CodecContext, Frame, &duration, &Packet);
}
This might be what you're looking for:
Codecs which have the CODEC_CAP_DELAY capability set have a delay
between input and output, these need to be fed with avpkt->data=NULL,
avpkt->size=0 at the end to return the remaining frames.
Link to FFmpeg documentation

ffmpeg recording h264 live stream got error

I am trying to record a h.264 live stream using the following code:
AVOutputFormat* fmt = av_guess_format(NULL, "test.mpeg", NULL);
AVFormatContext* oc = avformat_alloc_context();
oc->oformat = fmt;
avio_open2(&oc->pb, "test.mpeg", AVIO_FLAG_WRITE, NULL, NULL);
AVStream* stream = NULL;
...
while(!done)
{
// Read a frame
if(av_read_frame(inputStreamFormatCtx, &packet)<0)
return false;
if(packet.stream_index==correct_index)
{
////////////////////////////////////////////////////////////////////////
// Is this a packet from the video stream -> decode video frame
if (stream == NULL){//create stream in file
stream = avformat_new_stream(oc, pFormatCtx->streams[videoStream]->codec->codec);
avcodec_copy_context(stream->codec, pFormatCtx->streams[videoStream]->codec);
stream->sample_aspect_ratio = pFormatCtx->streams[videoStream]->codec->sample_aspect_ratio;
stream->sample_aspect_ratio.num = pFormatCtx->streams[videoStream]->codec->sample_aspect_ratio.num;
stream->sample_aspect_ratio.den = pFormatCtx->streams[videoStream]->codec->sample_aspect_ratio.den;
// Assume r_frame_rate is accurate
stream->r_frame_rate = pFormatCtx->streams[videoStream]->r_frame_rate;
stream->avg_frame_rate = stream->r_frame_rate;
stream->time_base = av_inv_q(stream->r_frame_rate);
stream->codec->time_base = stream->time_base;
avformat_write_header(oc, NULL);
}
av_write_frame(oc, &packet);
...
}
}
However, the ffmpeg says
encoder did not produce proper pts making some up
when the code runs to av_write_frame(); what's the problem here?
First make sure the inputStreamFormatCtx allocated and filled by right values (which is the cause of 90% of problem with demuxing/remuxing problems) - check some samples on internet to know how u should allocate and set its values.
The error tells us what is happening and it seems it is just a warning.
PTS (Presentation Time Stamp) is a number based on stream->time_base which tells us when we should show the decoded frame of this packet. when u get a live stream via network it's possible the server hasn't put a valid number for PTS of packet and when you receive the data it has a INVALID PTS (which you can find out by reading packet.pts and check if its a AV_NOPTS_VALUE). so then libav tries to generate the right pts based on frame rate and time_base of stream. It's a helpful attempt and if the recorded file can be played on a real motion (fps-wise) you should be happy. and if the recorded file will be played on a fast or slow motion (fps-wise) you got a problem and you can't rely on libav to correct the fps anymore. so then you should calculate the right fps by decoding the packets and then calculate the right pts based on the stream->time_base and set it to packet.pts.

avconv complains "non monotonically increasing dts to muxer in stream" when piping from libx264 on 14.04

I have a piece of code that takes a stream of images and writes them to a file using x264 to encode and avconv. The relevant bits are as follows
// Setup encoder
sprintf(cmd, "avconv -i pipe: -vcodec copy %s", filename);
fp = popen(cmd, "w");
x264_param_default_preset(&params, "ultrafast", "stillimage,zerolatency");
params.i_fps_num = fps;
params.i_fps_den = 1;
x264_picture_alloc(&in, X264_CSP_I420, width, height);
params.i_csp = X264_CSP_I420;
in.img.i_csp = X264_CSP_I420;
x.params.b_vfr_input = 0;
in.i_pts = -1;
out.i_pts = -1;
params.i_width = width;
params.i_height = height;
encoder = x264_encoder_open(&params);
in.img.i_plane = 1;
in.img.i_stride[0] = width;
ret = x264_encoder_headers(encoder, &nals, &nheader);
header_size = nals[0].i_payload + nals[1].i_payload + nals[2].i_payload;
fwrite(nals[0].p_payload, header_size, 1, fp);
...
// Loop body
++in.i_pts;
frame_size = x264_encoder_encode(encoder, &nals, &num_nals, &in, &out);
fwrite(nals[0].p_payload, frame_size, 1, fp);
I've left out error checking for clarity, but no error is ever returned. Indeed, until I upgraded my system to 14.04, this code worked perfectly (and continues to work perfectly for colleagues who've yet to upgrade).
Only now running Ubuntu 14.04, I get this output from avconv
[h264 # 0x98dec0] Estimating duration from bitrate, this may be inaccurate
Input #0, h264, from 'pipe:'
Duration: N/A, bitrate: N/A
Stream #0.0: Video: h264 (Constrained Baseline), yuv420p, 640x480, 25 fps, 25 tbr, 25 tbn, 60 tbc
Output #0, mp4, to '../reel/test.mp4':
Metadata:
encoder : Lavf54.20.3
Stream #0.0: Video: libx264, yuv420p, 640x480, q=2-31, 25 tbn, 25 tbc
Stream mapping:
Stream #0:0 -> #0:0 (copy)
[mp4 # 0x1347800] Application provided invalid, non monotonically increasing dts to muxer in stream 0: 2 >= 2
av_interleaved_write_frame(): Invalid argument
Despite the error, out.i_dts does monotonically increase over the whole duration of the video (it's always equal to in.i_pts).
My general assumption is that newer versions of avconv are more strict with the parameters of the input stream, so while my choice of parameters may have worked before, they do not work now.
Another curiousity, which might be related, is avconv detecting that the stream is 25 FPS, even though x264 is configured with an input FPS of 30.
Edit: Some further information, the same dts error (2>=2) happens regardless of the initial pts (with the output dts matching as expected).
In a moment of "I don't know why this should fix it, but does", changing -vcodec copy to -vcodec libx264 (even though the source codec was already libx264) fixed the dts error.

getting AVFrame pts value

I have a AVStream of Video from FormatContext. [ avstream ]
Read Packet
Decode packet if it is from video.
Now Display the following.
Packet DTS -> 7200.00 [ from packet ]
Frame PTS -> -9223372036854775808.000000
stream time_base -> 0.000011
Offset -> 0.080000 [ pts * time_base ]
code:
double pts = (double) packet.dts;
printf (" dts of packet %f , Frame pts: %f, timeBase %f Offset: %f ",
pts,
(double)pFrame->pts,
av_q2d (avstream->time_base) ,
pts
*av_q2d(avstream->time_base));
Why is Frame pts negative ? Is it expected behavior ?
Do I need to consider Frame pts from packet DTS [ ie: frame pts = packet
dts ]
The number you're seeing for PTS is -9223372036854775808 (0x8000000000000000) is also known as AV_NOPTS_VALUE. It means that there's no value available.
I couldn't find a solution when I was seeing this so after quite some time of banging my head against this, I ended up manually advancing my video clock when I saw this.
int64 pts = m_frame->pts;
if (pts == AV_NOPTS_VALUE)
{
pts = m_videoClock +
(1.f / av_q2d(stream->avg_frame_rate)) / av_q2d(stream->time_base);
}
m_videoClock = pts;
I don't think DTS is useful here because that represents when the packet decoded, which isn't a replacement for PTS.

Resources