Replies: 9 comments
-
I don't think we have encountered this behavior. PyAV yields packets/frames in the order that FFmpeg provides them, which has never been anything but Does this happen for all videos for you? |
Beta Was this translation helpful? Give feedback.
-
Thanks for your reply. I usually encounter this issue when reading avi/mkv files. For example, when reading https://filebin.ca/4lNZ9xo4YIFZ (a file taken from the HMDB51 dataset), the dts and pts returned by pyav (i.e.,
You can see that dts is increasing while pts is not. Interestingly, ffplay seems to play the video according to the dst order instead of pts. Maybe the pts returned by pyav is not correct? |
Beta Was this translation helpful? Give feedback.
-
|
Beta Was this translation helpful? Give feedback.
-
Thanks for pointing out this issue. Now the problem is clearer. I am not familiar with avi files. But I remember that avi files does not support variable frame rate. As the frame duration never changes, pts are not strictly required by avi files. In libav, pts may be AV_NOPTS_VALUE. In pyav, the pts seems to be always valid, and thus (i guess) leads to non-monotonic pts sequence for avi files with AV_NOPTS_VALUE. |
Beta Was this translation helpful? Give feedback.
-
We do assign a pts when encoding. I didn't do an exhaustive search for |
Beta Was this translation helpful? Give feedback.
-
If I put a Everything on PyAV's side is behaving normally. I don't know if there is anything reasonable to do here. |
Beta Was this translation helpful? Give feedback.
-
Interestingly, I write the following c code for testing (modified from http://dranger.com/ffmpeg/tutorial01.c). And it seems that frame->best_effort_timestamp can report the correct pts. // Use
//
// gcc -o test test.c -lavformat -lavcodec
//
// to build (assuming libavformat and libavcodec are correctly installed
// your system).
//
// Run using
//
// ./test input.avi
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <stdio.h>
// compatibility with newer API
#if LIBAVCODEC_VERSION_INT < AV_VERSION_INT(55, 28, 1)
#define av_frame_alloc avcodec_alloc_frame
#define av_frame_free avcodec_free_frame
#endif
int main(int argc, char *argv[])
{
// Initalizing these to NULL prevents segfaults!
AVFormatContext *pFormatCtx = NULL;
int i, videoStream;
AVCodecContext *pCodecCtxOrig = NULL;
AVCodecContext *pCodecCtx = NULL;
AVCodec *pCodec = NULL;
AVFrame *pFrame = NULL;
AVPacket packet;
int frameFinished;
if (argc < 2)
{
printf("Please provide a movie file\n");
return -1;
}
// Register all formats and codecs
av_register_all();
// Open video file
if (avformat_open_input(&pFormatCtx, argv[1], NULL, NULL) != 0)
return -1; // Couldn't open file
// Retrieve stream information
if (avformat_find_stream_info(pFormatCtx, NULL) < 0)
return -1; // Couldn't find stream information
// Find the first video stream
videoStream = -1;
for (i = 0; i < pFormatCtx->nb_streams; i++)
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
{
videoStream = i;
break;
}
if (videoStream == -1)
return -1; // Didn't find a video stream
// Get a pointer to the codec context for the video stream
pCodecCtxOrig = pFormatCtx->streams[videoStream]->codec;
// Find the decoder for the video stream
pCodec = avcodec_find_decoder(pCodecCtxOrig->codec_id);
if (pCodec == NULL)
{
fprintf(stderr, "Unsupported codec!\n");
return -1; // Codec not found
}
// Copy context
pCodecCtx = avcodec_alloc_context3(pCodec);
if (avcodec_copy_context(pCodecCtx, pCodecCtxOrig) != 0)
{
fprintf(stderr, "Couldn't copy codec context");
return -1; // Error copying codec context
}
// Open codec
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0)
return -1; // Could not open codec
// Allocate video frame
pFrame = av_frame_alloc();
// Read frames
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, &frameFinished, &packet);
// Did we get a video frame?
if (frameFinished)
{
printf("pts: %d\n", pFrame->best_effort_timestamp);
}
}
// Free the packet that was allocated by av_read_frame
av_free_packet(&packet);
}
// Free the YUV frame
av_frame_free(&pFrame);
// Close the codecs
avcodec_close(pCodecCtx);
avcodec_close(pCodecCtxOrig);
// Close the video file
avformat_close_input(&pFormatCtx);
return 0;
} |
Beta Was this translation helpful? Give feedback.
-
So.... how about exposing |
Beta Was this translation helpful? Give feedback.
-
I think exposing it as a property or something else is fine. However, according to #13, maybe this will lead to some incompatibility? |
Beta Was this translation helpful? Give feedback.
-
Currently, pyav returns frames according to dts. However, when we encode a video, we need to provide frames according to pts. Thus, I have to perform sorting between decoding & encoding like this (otherwise I will get an incorrect output video when there are B-frames in the input):
Is there a more efficient way?
Thanks in advance.
Beta Was this translation helpful? Give feedback.
All reactions