Skip to content

Commit 3a12c50

Browse files
committed
Fix timing of AVI files dumped on Linux
The timing information is set on s_scaled_frame->pts, giving precise timing information to the encoder. Frames arriving too early (less than one tick after the previous frame) are droped. The setting of packet's timestamps and flags is done after the call to avcodec_encode_video2() as this function resets these fields according to its documentation.
1 parent f65bb10 commit 3a12c50

File tree

1 file changed

+39
-11
lines changed

1 file changed

+39
-11
lines changed

Source/Core/VideoCommon/AVIDump.cpp

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include "Common/Logging/Log.h"
1515

1616
#include "Core/CoreTiming.h"
17+
#include "Core/HW/SystemTimers.h"
1718
#include "Core/HW/VideoInterface.h" //for TargetRefreshRate
1819
#include "VideoCommon/AVIDump.h"
1920
#include "VideoCommon/VideoConfig.h"
@@ -29,7 +30,6 @@
2930

3031
#include "Core/ConfigManager.h" // for EuRGB60
3132
#include "Core/CoreTiming.h"
32-
#include "Core/HW/SystemTimers.h"
3333

3434
static HWND s_emu_wnd;
3535
static LONG s_byte_buffer;
@@ -335,6 +335,7 @@ static int s_height;
335335
static int s_size;
336336
static u64 s_last_frame;
337337
bool b_start_dumping = false;
338+
static u64 s_last_pts;
338339

339340
static void InitAVCodec()
340341
{
@@ -352,6 +353,7 @@ bool AVIDump::Start(int w, int h)
352353
s_height = h;
353354

354355
s_last_frame = CoreTiming::GetTicks();
356+
s_last_pts = 0;
355357

356358
InitAVCodec();
357359
bool success = CreateFile();
@@ -416,14 +418,6 @@ static void PreparePacket(AVPacket* pkt)
416418
av_init_packet(pkt);
417419
pkt->data = nullptr;
418420
pkt->size = 0;
419-
if (s_stream->codec->coded_frame->pts != AV_NOPTS_VALUE)
420-
{
421-
pkt->pts = av_rescale_q(s_stream->codec->coded_frame->pts,
422-
s_stream->codec->time_base, s_stream->time_base);
423-
}
424-
if (s_stream->codec->coded_frame->key_frame)
425-
pkt->flags |= AV_PKT_FLAG_KEY;
426-
pkt->stream_index = s_stream->index;
427421
}
428422

429423
void AVIDump::AddFrame(const u8* data, int width, int height)
@@ -448,11 +442,45 @@ void AVIDump::AddFrame(const u8* data, int width, int height)
448442
// Encode and write the image.
449443
AVPacket pkt;
450444
PreparePacket(&pkt);
451-
int got_packet;
452-
int error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet);
445+
int got_packet = 0;
446+
int error = 0;
447+
u64 delta;
448+
s64 last_pts;
449+
if (!b_start_dumping && s_last_frame <= SystemTimers::GetTicksPerSecond())
450+
{
451+
delta = CoreTiming::GetTicks();
452+
last_pts = AV_NOPTS_VALUE;
453+
b_start_dumping = true;
454+
}
455+
else
456+
{
457+
delta = CoreTiming::GetTicks() - s_last_frame;
458+
last_pts = (s_last_pts * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond();
459+
}
460+
u64 pts_in_ticks = s_last_pts + delta;
461+
s_scaled_frame->pts = (pts_in_ticks * s_stream->codec->time_base.den) / SystemTimers::GetTicksPerSecond();
462+
if (s_scaled_frame->pts != last_pts)
463+
{
464+
s_last_frame = CoreTiming::GetTicks();
465+
s_last_pts = pts_in_ticks;
466+
error = avcodec_encode_video2(s_stream->codec, &pkt, s_scaled_frame, &got_packet);
467+
}
453468
while (!error && got_packet)
454469
{
455470
// Write the compressed frame in the media file.
471+
if (pkt.pts != AV_NOPTS_VALUE)
472+
{
473+
pkt.pts = av_rescale_q(pkt.pts,
474+
s_stream->codec->time_base, s_stream->time_base);
475+
}
476+
if (pkt.dts != AV_NOPTS_VALUE)
477+
{
478+
pkt.dts = av_rescale_q(pkt.dts,
479+
s_stream->codec->time_base, s_stream->time_base);
480+
}
481+
if (s_stream->codec->coded_frame->key_frame)
482+
pkt.flags |= AV_PKT_FLAG_KEY;
483+
pkt.stream_index = s_stream->index;
456484
av_interleaved_write_frame(s_format_context, &pkt);
457485

458486
// Handle delayed frames.

0 commit comments

Comments
 (0)