Skip to content

Commit

Permalink
Fix invalid starting PTS value, preventing blank 1st frames on some t…
Browse files Browse the repository at this point in the history
…humbnailing and video players.
  • Loading branch information
jonoomph committed Jun 25, 2021
1 parent 09eb807 commit bdf6e9f
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 55 deletions.
109 changes: 55 additions & 54 deletions src/FFmpegWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@ FFmpegWriter::FFmpegWriter(const std::string& path) :
info.has_audio = false;
info.has_video = false;

// Init timestamps
write_video_count = 0;
write_audio_count = 0;

// Initialize FFMpeg, and register all formats and codecs
AV_REGISTER_ALL

Expand Down Expand Up @@ -910,60 +914,63 @@ void FFmpegWriter::flush_encoders() {
}

// FLUSH AUDIO ENCODER
if (info.has_audio)
for (;;) {

// Increment PTS (in samples and scaled to the codec's timebase)
// for some reason, it requires me to multiply channels X 2
write_audio_count += av_rescale_q(audio_input_position / (audio_codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), av_make_q(1, info.sample_rate), audio_codec_ctx->time_base);

AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
pkt.pts = pkt.dts = write_audio_count;
if (info.has_audio) {
for (;;) {
AVPacket pkt;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
pkt.pts = pkt.dts = write_audio_count;

/* encode the image */
int error_code = 0;
int got_packet = 0;
/* encode the image */
int error_code = 0;
int got_packet = 0;
#if IS_FFMPEG_3_2
error_code = avcodec_send_frame(audio_codec_ctx, NULL);
error_code = avcodec_send_frame(audio_codec_ctx, NULL);
#else
error_code = avcodec_encode_audio2(audio_codec_ctx, &pkt, NULL, &got_packet);
error_code = avcodec_encode_audio2(audio_codec_ctx, &pkt, NULL, &got_packet);
#endif
if (error_code < 0) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code);
}
if (!got_packet) {
break;
}
if (error_code < 0) {
ZmqLogger::Instance()->AppendDebugMethod(
"FFmpegWriter::flush_encoders ERROR [" + (std::string) av_err2str(error_code) + "]",
"error_code", error_code);
}
if (!got_packet) {
break;
}

// Since the PTS can change during encoding, set the value again. This seems like a huge hack,
// but it fixes lots of PTS related issues when I do this.
pkt.pts = pkt.dts = write_audio_count;
// Since the PTS can change during encoding, set the value again. This seems like a huge hack,
// but it fixes lots of PTS related issues when I do this.
pkt.pts = pkt.dts = write_audio_count;

// Scale the PTS to the audio stream timebase (which is sometimes different than the codec's timebase)
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, audio_codec_ctx->time_base, audio_st->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, audio_codec_ctx->time_base, audio_st->time_base);
if (pkt.duration > 0)
pkt.duration = av_rescale_q(pkt.duration, audio_codec_ctx->time_base, audio_st->time_base);
// Scale the PTS to the audio stream timebase (which is sometimes different than the codec's timebase)
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, audio_codec_ctx->time_base, audio_st->time_base);
if (pkt.dts != AV_NOPTS_VALUE)
pkt.dts = av_rescale_q(pkt.dts, audio_codec_ctx->time_base, audio_st->time_base);
if (pkt.duration > 0)
pkt.duration = av_rescale_q(pkt.duration, audio_codec_ctx->time_base, audio_st->time_base);

// set stream
pkt.stream_index = audio_st->index;
pkt.flags |= AV_PKT_FLAG_KEY;
// set stream
pkt.stream_index = audio_st->index;
pkt.flags |= AV_PKT_FLAG_KEY;

// Write packet
error_code = av_interleaved_write_frame(oc, &pkt);
if (error_code < 0) {
ZmqLogger::Instance()->AppendDebugMethod("FFmpegWriter::flush_encoders ERROR [" + (std::string)av_err2str(error_code) + "]", "error_code", error_code);
}
// Write packet
error_code = av_interleaved_write_frame(oc, &pkt);
if (error_code < 0) {
ZmqLogger::Instance()->AppendDebugMethod(
"FFmpegWriter::flush_encoders ERROR [" + (std::string) av_err2str(error_code) + "]",
"error_code", error_code);
}

// deallocate memory for packet
AV_FREE_PACKET(&pkt);
}
// deallocate memory for packet
AV_FREE_PACKET(&pkt);
}

// Increment PTS (in samples and scaled to the codec's timebase)
// for some reason, it requires me to multiply channels X 2
write_audio_count += av_rescale_q(audio_input_position / (audio_codec_ctx->channels * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16)), av_make_q(1, info.sample_rate), audio_codec_ctx->time_base);
}

}

Expand Down Expand Up @@ -2042,8 +2049,7 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr<Frame> frame, AVFrame *fra
pkt.data = (uint8_t *) frame_final->data;
pkt.size = sizeof(AVPicture);

// Increment PTS (in frames and scaled to the codec's timebase)
write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base);
// Set PTS (in frames and scaled to the codec's timebase)
pkt.pts = write_video_count;

/* write the compressed frame in the media file */
Expand All @@ -2065,9 +2071,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr<Frame> frame, AVFrame *fra
pkt.size = 0;
pkt.pts = pkt.dts = AV_NOPTS_VALUE;

// Increment PTS (in frames and scaled to the codec's timebase)
write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base);

// Assign the initial AVFrame PTS from the frame counter
frame_final->pts = write_video_count;
#if USE_HW_ACCEL
Expand Down Expand Up @@ -2142,11 +2145,6 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr<Frame> frame, AVFrame *fra

/* if zero size, it means the image was buffered */
if (error_code == 0 && got_packet_ptr) {

// Since the PTS can change during encoding, set the value again. This seems like a huge hack,
// but it fixes lots of PTS related issues when I do this.
//pkt.pts = pkt.dts = write_video_count;

// set the timestamp
if (pkt.pts != AV_NOPTS_VALUE)
pkt.pts = av_rescale_q(pkt.pts, video_codec_ctx->time_base, video_st->time_base);
Expand Down Expand Up @@ -2176,6 +2174,9 @@ bool FFmpegWriter::write_video_packet(std::shared_ptr<Frame> frame, AVFrame *fra
#endif // USE_HW_ACCEL
}

// Increment PTS (in frames and scaled to the codec's timebase)
write_video_count += av_rescale_q(1, av_make_q(info.fps.den, info.fps.num), video_codec_ctx->time_base);

// Success
return true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/QtPlayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ namespace openshot

void QtPlayer::Play()
{
// Set mode to playing, and speed to normal
// Set mode to playing, and speed to normal
mode = PLAYBACK_PLAY;
Speed(1);

Expand Down

0 comments on commit bdf6e9f

Please sign in to comment.