Closed huiyiqun closed 2 years ago
I found that the real problem is that the first few frames(about 40 frames) of the original stream were lost during the transcode procedure.
Minimum program to reproduce the problem:
import av
i = av.open('./input.mov')
o = av.open('./output.mov', 'w')
input_stream = next(stream for stream in i.streams if isinstance(stream, av.video.stream.VideoStream))
output_stream = o.add_stream('libx264', 1/input_stream.rate)
output_stream.bit_rate = 4000000
output_stream.height = input_stream.height
output_stream.width = input_stream.width
for frame in i.decode(streams=(input_stream, )):
frame.pts = None
pkt = output_stream.encode(frame)
if pkt is not None:
o.mux(pkt)
while True:
pkt = output_stream.encode()
if pkt is None:
break
o.mux(pkt)
o.close()
It's very strange for me that I couldn't explain why, so I have to illustrate everything I have found:
nb_frame
is still correct, but if I try to list all the frames, the number of frames listed is less than nb_frame
.If I set the size of gop of the output_stream to 1, then the output video seems normal, but that's not acceptable.
Do you find this happens with every video you run through your script, or just specific ones? In either case, can you please upload (small) samples to https://www.dropbox.com/request/CV725W7HRqaSv4N3t3HK ?
Thanks,
Mike
Actually, every video.
For example a random video downloaded from youtube:
~> ffprobe -show_streams -select_streams v input.mp4 | grep nb_frames
nb_frames=34776
~> ffprobe -show_frames -select_streams v input.mp4 | grep \/FRAME | wc -l
34776
However, the video through the transcoding of my script:
~> ffprobe -show_streams -select_streams v output.mp4 | grep nb_frames
nb_frames=34776
~> ffprobe -show_frames -select_streams v output.mp4 | grep \/FRAME | wc -l
34716
I guess you could easily reproduce this phenomenon with an arbitary video. If needed, A sample will sitill be uploaded after I find a small one.
The current version (via pip install) does not encode at all:
pkt = videoOutStream.encode(frame)
File "av/video/stream.pyx", line 86, in av.video.stream.VideoStream.encode (src/av/video/stream.c:2974)
File "av/video/stream.pyx", line 147, in av.video.stream.VideoStream.encode (src/av/video/stream.c:2664)
File "av/utils.pyx", line 78, in av.utils.err_check (src/av/utils.c:1732) av.AVError: [Errno 38] Function not implemented
@kanehekili Have you checked that the encoder you chooses is included in your ffmpeg build?
It seems there is no new version recently.
@huiyiqun I stumbled upon the same problem and managed to solve it by changing the encoder. I replaced libx264
with libopenh264
.
You can list the encoders available on your system using the ffmpeg -codecs
command. On my machine it returns the following: DEV.LS h264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10 (decoders: h264 libopenh264) (encoders: libx264 libx264rgb libopenh264)
.
Got the same problem here. pyav 8.0.2 on macOS 10.15.7 (brew)
Feeding frames into libx264 for the first 42 frames never returned a packet.
When on finishing write I called encode()
without a frame, it returned a bunch of packets that, funny enough, matched my first 42 frames in terms of pts perfectly.
Circumvented the issue by doing so:
encode(frame)
returns nothing, proceedencode(frame)
returns a list of packets I check their PTS.
encode()
w/o params as well, sort by PTS and mux the bunch in turn.Thus I loose no more frames. Feels like a dirty hack but solved my problem all right.
Your description has nothing to do with PyAV - this is how h264 works.
Feeding frames into libx264 for the first 42 frames never returned a packet.
Yes. The muxer needs a bunch of frames before it can start to make packages - that's the intrinsic behaviour of any muxer that compresses. You'll experience that behaviour also if you using libavcodec/lib264 with C/C++.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
您的来信已收到,谢谢!陈雷同济大学测绘与地理信息学院Thanks for your attention.Chen Lei College of survey and geo-information of Tongji university
The closest I could get is that related lost frames issue has something to do with variable frame rate or frame rate rounding.
The thing is that my source video has variable frame rate of 239.548, while re-encoded (to 224x224) the same video with ffmpeg has fixed frame rate 240.
Both ffprobe shows and AV library show that source video has 341118 frames, but 341761 in re-encoded video.
341118*(240/239.548)-341118=643.65 which is very similar to (341761-341118) == 643 frame diff.
So, that must have something to do with variable frame rate or frame rate rounding.
The strangest thing is that ffmpeg exports correctly all frames but ffprobe displays less than real frame number: ffprobe -show_streams -select_streams v A704C95E-AAFA-42B5-8163-2FA8274F0279.mov | grep nb_frames
nb_frames=341118
ffprobe -show_streams -select_streams v A704C95E-AAFA-42B5-8163-2FA8274F0279_224.mov | grep nb_frames
nb_frames= 341761
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
您的来信已收到,谢谢!陈雷同济大学测绘与地理信息学院Thanks for your attention.Chen Lei College of survey and geo-information of Tongji university
I have a small application which decodes one stream, alters one of its planes, and then encodes and remuxes it into output container.
However, the first few frames of the output video seems has wrong time invervals(the video seems slowed down). And the application has following output:
I happens to find that the large negative number is extactly the
start_time
of the stream, while I'm not sure whether it's related.versions:
In case you need this: