Hi there,
I'm currently using the avcodec_decode_video function to decode a
sequence of H.264 frames. As I need to preserve the PTS I use the
reordered_opaque field of AVCodecContext to pass it through the decoding
process. As I get my input frame by frame I pass every frame to
avcodec_decode_video and check whether got_picture is unequal zero. When
decoding 720p50 content everything works perfectly, but when I try to
decode 1080i50 content there is some really awkward behaviour. I also
get my input "frame" by "frame" in this case (which means that I get
both top and bottom field in one buffer), but the decoder only outputs
around 12-13 frames per second, most of which are black or totally
distorted - except some key frames every once in a while. The really
strange thing now is this: if I call the avcodec_decode_video function
two times with the same buffer and the same AVPicture to store the final
picture in, the decoded pictures look good but the performance still
stays at the level of the first case (around 12-13 frames per second).
Accepting the fact that I have to call this function twice (for whatever
reason, maybe some programming error on my side as I don't think that
this is by design, or is it?) I tried to play around with the number of
threads and the two threading methods (frame and slice based) available.
Currently I'm using two threads and slice based decoding which leads to
the 12-13 frames per second I described. When using more threads (less
than or equal to 16) this doesn't change, if I use more the got_picture
flag is never unequal zero and no frames are returned at all. When using
frame based threading the application starts hanging after the second or
third call of avcodec_video_decode (not always the same as my input is
live satellite material and therefore seldom being repeated). I already
thought about putting multiple frames (meaning multiple associated top
and bottom fields) into a buffer and pass it to avcodec_video_decode but
what about my PTS values then? How am I able to preserve them? One last
note concerning decoding speed: I'm currently using an eight core state
of the art server, so CPU power should not be a concern - at least not
if multiple threads can be used. My application is the only one running
on the server at the moment. Here is the imporant part of the code:
... The codec context initialization:
codeccontext = avcodec_alloc_context2(CODEC_TYPE_VIDEO);
if (!codeccontext)
{
fprintf(stderr, "Error allocating codec context");
return false;
}
/*codeccontext->thread_count = 2;
codeccontext->thread_type = FF_THREAD_FRAME;*/
codeccontext->thread_count = 8;
codeccontext->thread_type = FF_THREAD_SLICE;
if (avcodec_open(codeccontext, avcodec_find_decoder_by_name("h264") !=
0)
{
fprintf(stderr, "Invalid codec context");
return false;
}
... For every frame do the following:
codeccontext->reordered_opaque = frame_pts;
int len = 0;
while ((len = avcodec_decode_video(codeccontext, frame, &finished,
buffer, bufferSize)) < bufferSize && len > 0)
{
fprintf(stderr, "%d bytes left for decoding (%s)", bufferSize -
len, finished ? "finished" : "unfinished"); //When slice based threading
is used this message never appears; if frame based threading is used
this message sometimes appears, always with got_frame unfinished
buffer += len;
bufferSize -= len;
}
if (!finished && interlaced) //Decode again (for whatever reason) to
get pictures which are not distorted
{
buffer = originalBuffer;
bufferSize = originalBufferSize;
codeccontext->reordered_opaque = frame_pts;
len = 0;
while ((len = avcodec_decode_video(codeccontext, frame, &finished,
buffer, bufferSize)) < bufferSize && len > 0)
{
fprintf(stderr, "%d bytes left for decoding (%s)", bufferSize -
len, finished ? "finished" : "unfinished"); //When slice based threading
is used this message never appears; if frame based threading is used
this message sometimes appears, always with got_frame unfinished
buffer += len;
bufferSize -= len;
}
}
if (finished)
{
rawdatasize = avpicture_get_size(codeccontext->pix_fmt,
codeccontext->width, codeccontext->height);
rawdata = (UBYTE*)malloc(rawdatasize);
int tempdatasize = avpicture_get_size(codeccontext->pix_fmt,
codeccontext->width, codeccontext->height);
UBYTE *tempdata = (UBYTE*)malloc(tempdatasize);
if (avpicture_fill((AVPicture*)deinterlacedframe, tempdata,
codeccontext->pix_fmt, codeccontext->width, codeccontext->height) <= 0)
//>0 means successful
{
fprintf(stderr, "Unexpected error prior deinterlacing");
free(tempdata);
free(buffer);
continue;
}
if (avpicture_deinterlace((AVPicture*)deinterlacedframe, (const
AVPicture*)frame, codeccontext->pix_fmt, codeccontext->width,
codeccontext->height) != 0)
{
fprintf(stderr, "Deinterlacing error");
free(tempdata);
free(buffer);
continue;
}
//TODO: Rescale frame
avpicture_layout((AVPicture*)deinterlacedframe, PIX_FMT_YUV420P,
codeccontext->width, codeccontext->height, rawdata, rawdatasize);
The most important questions: why do I have to call avcodec_decode_video
twice (what am I doing wrong here) for interlaced material in order to
get pictures which are not distorted? Why is the decoding speed
insufficient (it's definitely not the lack of CPU power)? Any why does
the whole program hand when calling avcodec_decode_video with frame
based threading? Is that because there is only one frame (two fields) in
my buffer and if so, how can I preserve my PTS when passing multiple
frames?
Regards,
Andreas
_______________________________________________
libav-user mailing list
[email protected]
https://lists.mplayerhq.hu/mailman/listinfo/libav-user