mirror of
https://github.com/horgh/videostreamer.git
synced 2025-09-26 12:31:18 +08:00
Support input with non-monotonic dts
This fixes issue #1. It appears there are inputs where the dts fluctuates. This is apparently inputs that are not well formed. However, I discovered that ffmpeg itself allows for this. If it detects this happening, it updates the pts/dts of the packet. To do this, it tracks the last output dts. This ensures the output dts is monotonic even if the input is not. I use essentially the same approach as in ffmpeg.
This commit is contained in:
@@ -239,6 +239,8 @@ vs_open_output(const char * const output_format_name,
|
||||
av_dict_free(&opts);
|
||||
|
||||
|
||||
output->last_dts = 0;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
@@ -319,8 +321,7 @@ vs_read_packet(const struct VSInput * input, AVPacket * const pkt,
|
||||
// 1 if we wrote the packet
|
||||
int
|
||||
vs_write_packet(const struct VSInput * const input,
|
||||
const struct VSOutput * const output, AVPacket * const pkt,
|
||||
const bool verbose)
|
||||
struct VSOutput * const output, AVPacket * const pkt, const bool verbose)
|
||||
{
|
||||
if (!input || !output || !pkt) {
|
||||
printf("%s\n", strerror(EINVAL));
|
||||
@@ -357,6 +358,45 @@ vs_write_packet(const struct VSInput * const input,
|
||||
return -1;
|
||||
}
|
||||
|
||||
// It is possible that the input is not well formed. Its dts (decompression
|
||||
// timestamp) may fluctuate. av_write_frame() says that the dts must be
|
||||
// strictly increasing.
|
||||
//
|
||||
// Packets from such inputs might look like:
|
||||
//
|
||||
// in: pts:18750 pts_time:0.208333 dts:18750 dts_time:0.208333 duration:3750 duration_time:0.0416667 stream_index:1
|
||||
// in: pts:0 pts_time:0 dts:0 dts_time:0 duration:3750 duration_time:0.0416667 stream_index:1
|
||||
//
|
||||
// dts here is 18750 and then 0.
|
||||
//
|
||||
// If we try to write the second packet as is, we'll see this error:
|
||||
// [mp4 @ 0x10f1ae0] Application provided invalid, non monotonically increasing dts to muxer in stream 1: 18750 >= 0
|
||||
//
|
||||
// This is apparently a fairly common problem. In ffmpeg.c (as of ffmpeg
|
||||
// 3.2.4 at least) there is logic to rewrite the dts and warn if it happens.
|
||||
// Let's do the same. Note my logic is a little different here.
|
||||
if (pkt->dts != AV_NOPTS_VALUE && output->last_dts != AV_NOPTS_VALUE &&
|
||||
pkt->dts < output->last_dts) {
|
||||
int64_t const next_dts = output->last_dts+1;
|
||||
|
||||
if (verbose) {
|
||||
printf("Warning: Non-monotonous DTS in input stream. Previous: %" PRId64 " current: %" PRId64 ". changing to %" PRId64 ".\n",
|
||||
output->last_dts, pkt->dts, next_dts);
|
||||
}
|
||||
|
||||
// We also apparently (ffmpeg.c does this too) need to update the pts.
|
||||
// Otherwise we see an error like:
|
||||
//
|
||||
// [mp4 @ 0x555e6825ea60] pts (3780) < dts (22531) in stream 0
|
||||
|
||||
if (pkt->pts != AV_NOPTS_VALUE && pkt->pts >= pkt->dts) {
|
||||
pkt->pts = FFMAX(pkt->pts, next_dts);
|
||||
}
|
||||
|
||||
pkt->dts = next_dts;
|
||||
}
|
||||
|
||||
|
||||
// Set pts/dts if not set. Otherwise we will receive warnings like
|
||||
//
|
||||
// [mp4 @ 0x55688397bc40] Timestamps are unset in a packet for stream 0. This
|
||||
@@ -388,6 +428,10 @@ vs_write_packet(const struct VSInput * const input,
|
||||
}
|
||||
|
||||
|
||||
// Track last dts we see (see where we use it for why).
|
||||
output->last_dts = pkt->dts;
|
||||
|
||||
|
||||
// Write encoded frame (as a packet).
|
||||
|
||||
// av_interleaved_write_frame() works too, but I don't think it is needed.
|
||||
|
@@ -3,6 +3,7 @@
|
||||
|
||||
#include <libavformat/avformat.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct VSInput {
|
||||
AVFormatContext * format_ctx;
|
||||
@@ -11,6 +12,13 @@ struct VSInput {
|
||||
|
||||
struct VSOutput {
|
||||
AVFormatContext * format_ctx;
|
||||
|
||||
// Track the last dts we output. We use it to double check that dts is
|
||||
// monotonic.
|
||||
//
|
||||
// I am not sure if it is available anywhere already. I tried
|
||||
// AVStream->info->last_dts and that is apparently not set.
|
||||
int64_t last_dts;
|
||||
};
|
||||
|
||||
void
|
||||
@@ -37,7 +45,6 @@ vs_read_packet(const struct VSInput *, AVPacket * const,
|
||||
|
||||
int
|
||||
vs_write_packet(const struct VSInput * const,
|
||||
const struct VSOutput * const, AVPacket * const,
|
||||
const bool);
|
||||
struct VSOutput * const, AVPacket * const, const bool);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user