Hello!
Here is a https://github.com/bytedeco/javacv/blob/9c92f58038b1b0ead22c15c778be4b374de955ba/src/main/java/org/bytedeco/javacv/FFmpegFrameGrabber.java#L447 method. if oc.start_time() gives negative value and you setting timestamp less then this value, then timestamp will be also negative and
while (this.timestamp > timestamp + 1 && grabFrame(false, true, false, false) != null && count++ < 1000) {
// flush frames if seeking backwards
}
where this.timestamp is 0 by default, will skip 1000 movie frames (whole video in 1.3.3 version).
Theoretically I can create some fix for this, but I think this while loops have a purpose, but I do not know which.
Thank you!
The purpose is stated right there:
// flush frames if seeking backwards
I still don't understand what the problem is. If the timestamps are not increasing, then doesn't this mean that the stream isn't seekable?
@saudet
this.timestamp is 0 by default and always increased after every grabFrame call
timestamp + 1 is negative, because oc.start_time() is negative.
So in while loop this.timestamp > timestamp + 1 it always true and loop will run until count < 1000 (to the end of the video in 1.3.3 version, because there is no count check).
Should I create an example, or you getting an idea?
Thank you for fast reply!
So, decrease the value passed to setTimestamp()?
@saudet
Here is an example.
public static void test() throws Exception {
File out = new File("out.mp4");
try (FFmpegFrameGrabber video = new FFmpegFrameGrabber(
"https://www.dropbox.com/s/kiez6tl8uqaq9jh/VeryShortVideo.mp4?dl=1")) {
video.start();
try (FFmpegFrameRecorder rec = new FFmpegFrameRecorder(out, video.getImageWidth(), video.getImageHeight(),
video.getAudioChannels())) {
rec.start();
System.out.println(video.getTimestamp());
video.setTimestamp(0);
System.out.println(video.getTimestamp());
}
}
}
After setting timestamp video.setTimestamp(0) I got 15666666 timestamp, and this is the end of the video. (Im using javacv 1.3.3).
For now I handling this problem with this wrapper
public static void setTimestamp(FFmpegFrameGrabber video, long microStart) throws Exception {
// handling video.getFormatContext().start_time() can be negative!
// we also can`t set 0 because it is spoils the first frame
if (video.getFormatContext().start_time() + microStart > 0) {
video.setTimestamp(microStart);
}
}
The MP4 format doesn't usually support seeking when reading like that from an HTTP stream. Does the same thing happen when first copied to a file on your local storage and then opened with FFmpeg?
@saudet
Yes. It is the same with exactly this file on local. I upload file to dropbox to show you an example exactly with this file. (Because video.getFormatContext().start_time() of this file gives negative value).
Do not think that the problem is with the "seeking", how it can seek to the negative timestamp value?
Does seeking work alright with players like ffplay?
@saudet
How can I check this? Open video with the player and change time?
It will be hard to check, because all this situation happens just with first 21678 microseconds (video.getFormatContext().start_time() returns -21678).
Also I still do not understand how it can be related to seeking. I think it is video.setTimestamp(0); problem with this loop
while (this.timestamp > timestamp + 1 && grabFrame(false, true, false, false) != null) {
// flush frames if seeking backwards
}
So you're saying ffplay doesn't have any problems with that file?
ffplay doesn't appear to do that kind of flushing... In any case, since your file is reporting to start at -21678, but it cannot seek there, it sounds like it's broken. Are you saying that your file is not corrupted? If so, could you explain how we should be able to seek to -21678?
@saudet Im not saying that my file is not corrupted, I do not know that, it is just one the files that have some problems. That is why I create this issue... even if it is corrupted, setTimestamp should work somehow and skip all the video is not the best way to work =)
For example we can do something that I did in my fix.. (set timestamp just if it is positive), but I do not know how it will affect any other files.
Thank you for your replies!
It sounds like if we called setTimestamp(21678) it would work as needed, wouldn't it?
@saudet
From side of skipping video - YES!
But I also saw, that getting frame after setTimestamp(0) spoils the first frame.. but this is a different story =) May be it is related to some other negative values.. Don`t know, will investigate and will create an issue with example if I found something.
Well, that's strange, from JavaCV we get this info:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'VeryShortVideo.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
title : 1043084642493887
encoder : Lavf56.40.101
Duration: 00:00:16.28, start: -0.021678, bitrate: 308 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 400x400 [SAR 1:1 DAR 1:1], 293 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (HE-AACv2) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 19 kb/s (default)
Metadata:
handler_name : SoundHandler
While from the ffprobe or ffmpeg program we get this:
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'VeryShortVideo.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
title : 1043084642493887
encoder : Lavf56.40.101
Duration: 00:00:16.28, start: 0.000000, bitrate: 308 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p, 400x400 [SAR 1:1 DAR 1:1], 293 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
Metadata:
handler_name : VideoHandler
Stream #0:1(und): Audio: aac (HE-AACv2) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 19 kb/s (default)
Metadata:
handler_name : SoundHandler
So it looks like there is something that we need to set in order to get the right start time...
@saudet, it seems that I faced a problem closely related to this issue. Excuse me for this very long description...
The problem appears when I use FFmpegFrameGrabber with some of video I have encoded previously by XviD with the packed bitstream option. Although cli ffmpeg dislikes this encoding option
(... Video uses a non-standard and wasteful way to store B-frames ('packed B-frames')...)
it can normally extract all frames from thus encoded files. Moreover, they can be played normally with various software players (including ffplay), they can be opened with tools like VirtualDub or avisynth. I mean that all frames are played/extracted in proper order with all those tools. I generated a short test video of n frames with all frames numbered from 0 to n-1 to check how frames are grabbed.
So, the issue with FFmpegFrameGrabber is following. When the grabber is created and video frames are grabbed one by one like that
grabber = new FFmpegFrameGrabber(path);
Frame frame = grabber.grabFrame(false, true, true, false); //called in loop
everything is fine, grabFrame returns frames in proper order, from 0 to n-1, with timestamps starting with 0 and increasing by 1/framerate.
But then if I seek to a frame number i with
grabber.setFrameNumber(i);
Frame frame = grabber.grabFrame(false, true, true, false);
the different result is obtained:
With i>=1, grabFrame called after setFrameNumber(i) returns frame i-1 (that is the previous one, e.g. it returns frame 0 if the frame i=1 is requested), but nevertheless, the timestamp of those frames correspond to the frame i.
With i=0 setFrameNumber(0) ends up with the last frame of the video instead of the first (I suppose that it would result in the frame 1000 in case of longer video, according to the code setTimestamp(long timestamp) function). Thus, the seeking causes a shift in the frame sequence/timestamps, and prevents correct seeking to the start of video.
When I encode same video without that option of packed bitstream no problems like that appear. Of course, it means that the issue only appears with those bad "packed bitstream" files. But it seems to me, that these bad files show that the following part of setTimestamp(long timestamp) is improper (or it may be as well that I do not understand it):
int count = 0; // prevent infinite loops with corrupted files
while (this.timestamp > timestamp + 1 && grabFrame(true, true, false, false) != null && count++ < 1000) {
// flush frames if seeking backwards
}
Every successful call of grabFrame increases this.timestamp. Is it correct? (I guess it from
long pts = av_frame_get_best_effort_timestamp(picture);
AVRational time_base = video_st.time_base();
timestamp = 1000000L * pts * time_base.num() / time_base.den();
in the grabFrame function). The function av_frame_get_best_effort_timestamp is designed to return monotonously increasing timestamps, AFAIK. Then if this.timestamp is initially <= than the required timestamp the loop will never work. But if this.timestamp is initially > than timestamp + 1, then the repeating calls of grabFrame will bring us far beyond the requested timestamp (to the end of a short video, or to some frame located 1000 steps ahead). If so, then this while loop is completely useless and should be removed.
In this view, I do not understand the comment " // flush frames if seeking backwards". As if it is supposed that every next grabFrame(...) in the loop rewinds the file towards the start. I'm confused by this... Can it be possible?
On opposite, the next while loop:
count = 0;
while (this.timestamp < timestamp - 1 && grabFrame(true, true, false, false) != null && count++ < 1000) {
// decode up to the desired frame
}
seems to work just as necessary. It grabs frame-by-frame till the desired timestamp reached (and it accounts for the possibility of rounding to timestamp-1). And as I can suggest, this is the only necessary loop of these two.
But all this will work if this.timestamp is set to some position before the desired timestamp after the seeking part of the code
if ((ret = avformat_seek_file(oc, -1, Long.MIN_VALUE, timestamp, Long.MAX_VALUE, AVSEEK_FLAG_BACKWARD)) < 0) {
throw new Exception("avformat_seek_file() error " + ret + ": Could not seek file to timestamp " + timestamp + ".");
}
if (video_c != null) {
avcodec_flush_buffers(video_c);
}
if (audio_c != null) {
avcodec_flush_buffers(audio_c);
}
if (pkt2.size() > 0) {
pkt2.size(0);
av_packet_unref(pkt);
}
I'm not sure if this.timestamp is set somehow in this code as here are only calls of native functions, not touching the grabber class member "timestamp". (BTW, I do not understand where from @gkozyryatskyy concludes that
where this.timestamp is 0 by default,
It is zero just after the construction, but it is changed by (almost) every call of grabeFrame)
So, I think that we should first obtain the current timestamp of the position set by avformat_seek_file(...).
With something like the previously mentioned av_frame_get_best_effort_timestamp(picture); After that we can do the while loop (// decode up to the desired frame).
Again, I'm not sure if I understand all this mechanics correctly.... Sorry, if I'm wrong.
And one more thing. As for the best guess of the frameNumber in the following code:
long pts = av_frame_get_best_effort_timestamp(picture);
AVRational time_base = video_st.time_base();
timestamp = 1000000L * pts * time_base.num() / time_base.den();
// best guess, AVCodecContext.frame_number = number of decoded frames...
frameNumber = (int)(timestamp * getFrameRate() / 1000000L);
It may be better to do round() instead of truncation by (int) cast. I often observed that frameNumbers are not increasing monotonously with timestamps because of the truncation (say, a frameNumber like 0.9999 is obviously truncated to zero) .
@anotherche Are you also observing a discrepancy with ffprobe and ffplay?
@saudet, Actually, I do not know how to extract metadata with FFmpegFrameGrabber (you have shown an info output from JavaCV above). I have tried getVideoMetadata() and getVideoMetadata(key) functions, but they return no info. How to use them?
I will attach two short files encoded with "the packed bitstream on" and without it.
example.zip They both have 26 frames numbered from 0 to 25, encoded at 25 fps.
By the way, I probably understand now the necessity of the first while loop
int count = 0; // prevent infinite loops with corrupted files
while (this.timestamp > timestamp + 1 && grabFrame(true, true, false, false) != null && count++ < 1000) {
// flush frames if seeking backwards
}
I was wrong about it in the previous message. The following is how I think it works.
When we are seeking backwards the initial this.timestamp is obviously greater then the requested timestamp. Then the function avformat_seek_file(...) and several lines of the code
f ((ret = avformat_seek_file(oc, -1, Long.MIN_VALUE, timestamp, Long.MAX_VALUE, AVSEEK_FLAG_BACKWARD)) < 0) {
throw new Exception("avformat_seek_file() error " + ret + ": Could not seek file to timestamp " + timestamp + ".");
}
if (video_c != null) {
avcodec_flush_buffers(video_c);
}
if (audio_c != null) {
avcodec_flush_buffers(audio_c);
}
if (pkt2.size() > 0) {
pkt2.size(0);
av_packet_unref(pkt);
}
should position the file decoding to a location just before the requested timestamp. So, if the file is not corrupted, the first call of grabFrame(...) in the first while loop following this code will give us the frame located at the requested timestamp (or just before this timestamp). As the result, the value of this.timestamp will change so that it will be at least <= timestamp+1, and the next run will not be done in the loop. Thus, this while loop will never work more than exactly once (if the file is not "corrupted" and the seeking works fine), and thus it can be replaced with a single conditional call of grabFrame(...).
In worse case (bad video) if the seeking will position the reading/decoding to some place AHEAD the requested timestamp, the first while loop will stop only after 1000 additional steps, or at the end of the video, or if some of successive calls of the grabFrame(...) will return null for some other reason. But it means that all those additional repetitions of this loop are not meaningful. And thus the while loop should be changed to a simple if(). Like that:
if (this.timestamp > timestamp + 1) grabFrame(true, true, false, false);
That's all with the backward seeking. This change should not break the logic for "good" video files, and it will improve the seeking behavior for "bad" video files.
As for the forward seeking, the second while loop should work fine in any case, It will grab frames until the requested timestamp will be reached.
Now I can see what happens with my files encoded with the packed bitstream option. For some reasons, there is a difference in sequences of timestamps and grabbed frames if they are grabbed right from the grabber.start(), or if they are grabbed after some seeking (does not matter, rewind or forward).
If frames are grabbed sequentially without any seeking I get a proper sequence of the frames but their timestamps are all shifted by 1000000/framerate. That is, if the framerate=25fps, I get the following sequence (grab calls are numbered from zero so that grab number 0 should ideally give us frame number 0, "frame obtained" is real frame in the video with its number hardcoded in the image)
grab number|frame obtained |timestamp
---------------|----------------|-------------
0|0|40000
1|1|80000
2|2|120000
3|3|160000
4|4|200000
and so on... Thus we have strange shift in the timestamps, as if the start time = 0.04 sec. But both ffprobe and ffplay report that
Input #0, avi, from 'film26-packed.avi':
Duration: 00:00:01.04, start: 0.000000, bitrate: 941 kb/s
But after a seeking is requested to any frame with number > 0 I get following
frame requested by setFrameNumber(i)|frame obtained |timestamp
---------------|----------------|-------------
1|0|40000
2|1|80000
3|2|120000
4|3|160000
5|4|200000
That is we have the same shift between the timestamps and obtained frames, but the timestamps correspond to the requested frames.
At last, if setFrameNumber(0) is called I get the last frame in the video and the grabber says that this.timestamp=0.
From this I guess that the last frame in the last case may be obtained as a result of the repeating calls of grabFrame(...) in the first while loop mentioned above. I think that when I ask to seek to the frame=0, the function avformat_seek_file(...) should obviously seek right to the beginning of the video. Then, the first call of the grabFrame(...) in the first while loop returns the frame number 0 which has timestamp=40000 according to the above tables. In the second run of the while loop, we have 40000>1 and, thus, do the second call of the grabFrame(...) which should return the frame number 1, and the timestamp=80000. And thus, we make following runs of this while loop because this.timestamp is always > than 1. Thus, the loop will go right to the last frame of the video.
Basically, I do not understand why, at the end, it returns the last frame. Because it should try to grabFrame once more and thus should return null (no more frames in the video). But instead it returns the last frame and says that its timestamp=0, and on the next run of the while() the timestamp=0 stops the running of the while loop.
Both files return the same start: 0.000000 as ffprobe, so your issue is not the same as this one.
Could you open a pull request that contains the changes that you propose? Thanks!
OK. I will do that.
Meanwhile I have found another interesting result with ffprobe which shows that there are problems with treating the start time in case of "packed b-frames" by ffmpeg.
As you said, ffprobe -i film26-packed.avi tells that start: 0.000000
But if to run a command showing more details on frames
ffprobe -i film26-packed.avi -show_frames -show_entries frame=pict_type,pkt_pts_time,pkt_dts_time,coded_picture_number,best_effort_timestamp_time -of json
it still tells that the start time is: start: 0.000000 but the first frame (which is Intra, so it should be shown first) actually starts at 0.04 sec:
Input #0, avi, from 'film26-packed.avi':
Duration: 00:00:01.04, start: 0.000000, bitrate: 941 kb/s
Stream #0:0: Video: mpeg4 (Advanced Simple Profile) (XVID / 0x44495658), yuv420p, 640x424 [SAR 1:1 DAR 80:53], 908 kb/s, 25 fps, 25 tbr, 25 tbn, 25 tbc
[mpeg4 @ 0000029e4daab260] Video uses a non-standard and wasteful way to store B-frames ('packed B-frames'). Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.
{
"frames": [
{
"pkt_dts_time": "0.040000",
"best_effort_timestamp_time": "0.040000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.080000",
"pkt_dts_time": "0.080000",
"best_effort_timestamp_time": "0.080000",
"pict_type": "B",
"coded_picture_number": 2
},
{
"pkt_dts_time": "0.120000",
"best_effort_timestamp_time": "0.120000",
"pict_type": "B",
"coded_picture_number": 3
},
{
"pkt_dts_time": "0.160000",
"best_effort_timestamp_time": "0.160000",
"pict_type": "P",
"coded_picture_number": 1
},
{
"pkt_pts_time": "0.200000",
"pkt_dts_time": "0.200000",
"best_effort_timestamp_time": "0.200000",
"pict_type": "B",
"coded_picture_number": 5
},
{
"pkt_dts_time": "0.240000",
"best_effort_timestamp_time": "0.240000",
"pict_type": "B",
"coded_picture_number": 6
},
{
"pkt_dts_time": "0.280000",
"best_effort_timestamp_time": "0.280000",
"pict_type": "P",
"coded_picture_number": 4
},
{
"pkt_pts_time": "0.320000",
"pkt_dts_time": "0.320000",
"best_effort_timestamp_time": "0.320000",
"pict_type": "B",
"coded_picture_number": 8
},
{
"pkt_dts_time": "0.360000",
"best_effort_timestamp_time": "0.360000",
"pict_type": "B",
"coded_picture_number": 9
},
{
"pkt_dts_time": "0.400000",
"best_effort_timestamp_time": "0.400000",
"pict_type": "P",
"coded_picture_number": 7
},
{
"pkt_pts_time": "0.440000",
"pkt_dts_time": "0.440000",
"best_effort_timestamp_time": "0.440000",
"pict_type": "B",
"coded_picture_number": 11
},
{
"pkt_dts_time": "0.480000",
"best_effort_timestamp_time": "0.480000",
"pict_type": "B",
"coded_picture_number": 12
},
{
"pkt_dts_time": "0.520000",
"best_effort_timestamp_time": "0.520000",
"pict_type": "P",
"coded_picture_number": 10
},
{
"pkt_pts_time": "0.560000",
"pkt_dts_time": "0.560000",
"best_effort_timestamp_time": "0.560000",
"pict_type": "B",
"coded_picture_number": 14
},
{
"pkt_dts_time": "0.600000",
"best_effort_timestamp_time": "0.600000",
"pict_type": "B",
"coded_picture_number": 15
},
{
"pkt_dts_time": "0.640000",
"best_effort_timestamp_time": "0.640000",
"pict_type": "P",
"coded_picture_number": 13
},
{
"pkt_pts_time": "0.680000",
"pkt_dts_time": "0.680000",
"best_effort_timestamp_time": "0.680000",
"pict_type": "B",
"coded_picture_number": 17
},
{
"pkt_dts_time": "0.720000",
"best_effort_timestamp_time": "0.720000",
"pict_type": "B",
"coded_picture_number": 18
},
{
"pkt_dts_time": "0.760000",
"best_effort_timestamp_time": "0.760000",
"pict_type": "P",
"coded_picture_number": 16
},
{
"pkt_pts_time": "0.800000",
"pkt_dts_time": "0.800000",
"best_effort_timestamp_time": "0.800000",
"pict_type": "B",
"coded_picture_number": 20
},
{
"pkt_dts_time": "0.840000",
"best_effort_timestamp_time": "0.840000",
"pict_type": "B",
"coded_picture_number": 21
},
{
"pkt_dts_time": "0.880000",
"best_effort_timestamp_time": "0.880000",
"pict_type": "P",
"coded_picture_number": 19
},
{
"pkt_pts_time": "0.920000",
"pkt_dts_time": "0.920000",
"best_effort_timestamp_time": "0.920000",
"pict_type": "B",
"coded_picture_number": 23
},
{
"pkt_dts_time": "0.960000",
"best_effort_timestamp_time": "0.960000",
"pict_type": "B",
"coded_picture_number": 24
},
{
"pkt_dts_time": "1.000000",
"best_effort_timestamp_time": "1.000000",
"pict_type": "P",
"coded_picture_number": 22
},
{
"pict_type": "P",
"coded_picture_number": 25
}
]
}
Another interesting detail is obtained if to force -f lavfi, that is virtually decode the source file:
ffprobe -f lavfi -i "movie=film26-packed.avi[out0]" -show_frames -show_entries frame=pict_type,pkt_pts_time,pkt_dts_time,coded_picture_number,best_effort_timestamp_time -of json
It tells now that the start time is 0.04!
[mpeg4 @ 00000258a8444e80] Video uses a non-standard and wasteful way to store B-frames ('packed B-frames'). Consider using the mpeg4_unpack_bframes bitstream filter without encoding but stream copy to fix it.
Input #0, lavfi, from 'movie=film26-packed.avi[out0]':
Duration: N/A, start: 0.040000, bitrate: N/A
Stream #0:0: Video: rawvideo (I420 / 0x30323449), yuv420p, 640x424 [SAR 1:1 DAR 80:53], 25 tbr, 25 tbn, 25 tbc
{
"frames": [
{
"pkt_pts_time": "0.040000",
"pkt_dts_time": "0.040000",
"best_effort_timestamp_time": "0.040000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.080000",
"pkt_dts_time": "0.080000",
"best_effort_timestamp_time": "0.080000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.120000",
"pkt_dts_time": "0.120000",
"best_effort_timestamp_time": "0.120000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.160000",
"pkt_dts_time": "0.160000",
"best_effort_timestamp_time": "0.160000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.200000",
"pkt_dts_time": "0.200000",
"best_effort_timestamp_time": "0.200000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.240000",
"pkt_dts_time": "0.240000",
"best_effort_timestamp_time": "0.240000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.280000",
"pkt_dts_time": "0.280000",
"best_effort_timestamp_time": "0.280000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.320000",
"pkt_dts_time": "0.320000",
"best_effort_timestamp_time": "0.320000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.360000",
"pkt_dts_time": "0.360000",
"best_effort_timestamp_time": "0.360000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.400000",
"pkt_dts_time": "0.400000",
"best_effort_timestamp_time": "0.400000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.440000",
"pkt_dts_time": "0.440000",
"best_effort_timestamp_time": "0.440000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.480000",
"pkt_dts_time": "0.480000",
"best_effort_timestamp_time": "0.480000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.520000",
"pkt_dts_time": "0.520000",
"best_effort_timestamp_time": "0.520000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.560000",
"pkt_dts_time": "0.560000",
"best_effort_timestamp_time": "0.560000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.600000",
"pkt_dts_time": "0.600000",
"best_effort_timestamp_time": "0.600000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.640000",
"pkt_dts_time": "0.640000",
"best_effort_timestamp_time": "0.640000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.680000",
"pkt_dts_time": "0.680000",
"best_effort_timestamp_time": "0.680000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.720000",
"pkt_dts_time": "0.720000",
"best_effort_timestamp_time": "0.720000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.760000",
"pkt_dts_time": "0.760000",
"best_effort_timestamp_time": "0.760000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.800000",
"pkt_dts_time": "0.800000",
"best_effort_timestamp_time": "0.800000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.840000",
"pkt_dts_time": "0.840000",
"best_effort_timestamp_time": "0.840000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.880000",
"pkt_dts_time": "0.880000",
"best_effort_timestamp_time": "0.880000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.920000",
"pkt_dts_time": "0.920000",
"best_effort_timestamp_time": "0.920000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "0.960000",
"pkt_dts_time": "0.960000",
"best_effort_timestamp_time": "0.960000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "1.000000",
"pkt_dts_time": "1.000000",
"best_effort_timestamp_time": "1.000000",
"pict_type": "I",
"coded_picture_number": 0
},
{
"pkt_pts_time": "1.040000",
"pkt_dts_time": "1.040000",
"best_effort_timestamp_time": "1.040000",
"pict_type": "I",
"coded_picture_number": 0
}
]
}
There is no such problems with the file encoded without the packed b-frames - any type of ffprobe analysis returns start time = 0, and the first frame always has timestamp=0.
Thus, at least with this example, it means that the packed b-frames encoding does a hidden shift in the start time = 1/framerate
I've confirmed that the changes @anotherche generously contributed with pull #908 fixes this issue, and have been released with JavaCV 1.4.1. Enjoy!
Also tested it.. seems like it is working correctly! Thank you guys!