summaryrefslogtreecommitdiff
path: root/libavformat/dhav.c
diff options
context:
space:
mode:
authorPaul B Mahol <onemda@gmail.com>2019-12-25 19:35:27 +0100
committerPaul B Mahol <onemda@gmail.com>2019-12-25 22:10:47 +0100
commite3dca0744d21aa8d2c6f31f74a0e2142376333e1 (patch)
tree7f1913d1a0f9f37d9b10cf22078d1f67ba189a38 /libavformat/dhav.c
parentd6553e2e60a389296dd2f83a96f944ccfa5877a0 (diff)
avformat/dhav: improve seeking
Diffstat (limited to 'libavformat/dhav.c')
-rw-r--r--libavformat/dhav.c211
1 files changed, 130 insertions, 81 deletions
diff --git a/libavformat/dhav.c b/libavformat/dhav.c
index 120b8e4318..5e9abdb611 100644
--- a/libavformat/dhav.c
+++ b/libavformat/dhav.c
@@ -40,6 +40,7 @@ typedef struct DHAVContext {
int audio_codec;
int sample_rate;
int64_t last_good_pos;
+ int64_t duration;
int video_stream_index;
int audio_stream_index;
@@ -47,6 +48,7 @@ typedef struct DHAVContext {
typedef struct DHAVStream {
int64_t last_timestamp;
+ int64_t last_time;
int64_t pts;
} DHAVStream;
@@ -66,77 +68,6 @@ static int dhav_probe(const AVProbeData *p)
return 0;
}
-static int dhav_read_header(AVFormatContext *s)
-{
- DHAVContext *dhav = s->priv_data;
- uint8_t signature[5];
-
- ffio_ensure_seekback(s->pb, 5);
- avio_read(s->pb, signature, sizeof(signature));
- if (!memcmp(signature, "DAHUA", 5)) {
- avio_skip(s->pb, 0x400 - 5);
- dhav->last_good_pos = avio_tell(s->pb);
- } else {
- if (!memcmp(signature, "DHAV", 4)) {
- avio_seek(s->pb, -5, SEEK_CUR);
- dhav->last_good_pos = avio_tell(s->pb);
- } else if (s->pb->seekable) {
- avio_seek(s->pb, avio_size(s->pb) - 8, SEEK_SET);
- while (avio_rl32(s->pb) == MKTAG('d','h','a','v')) {
- int seek_back;
-
- seek_back = avio_rl32(s->pb) + 8;
- dhav->last_good_pos = avio_tell(s->pb);
- if (dhav->last_good_pos < seek_back)
- break;
- avio_seek(s->pb, -seek_back, SEEK_CUR);
- }
- }
- }
-
- s->ctx_flags |= AVFMTCTX_NOHEADER;
- dhav->video_stream_index = -1;
- dhav->audio_stream_index = -1;
-
- return 0;
-}
-
-static int64_t get_pts(AVFormatContext *s, DHAVStream *st)
-{
- DHAVContext *dhav = s->priv_data;
- /*
- int year, month, day, hour, min, sec;
- struct tm timeinfo;
-
- sec = dhav->date & 0x3F;
- min = (dhav->date >> 6) & 0x3F;
- hour = (dhav->date >> 12) & 0x1F;
- day = (dhav->date >> 17) & 0x1F;
- month = (dhav->date >> 22) & 0x0F;
- year = ((dhav->date >> 26) & 0x3F) + 2000;
-
- timeinfo.tm_year = year - 1900;
- timeinfo.tm_mon = month - 1;
- timeinfo.tm_mday = day;
- timeinfo.tm_hour = hour;
- timeinfo.tm_min = min;
- timeinfo.tm_sec = sec;*/
-
- if (st->last_timestamp == AV_NOPTS_VALUE) {
- st->last_timestamp = dhav->timestamp;
- }
-
- if (st->last_timestamp <= dhav->timestamp) {
- st->pts += dhav->timestamp - st->last_timestamp;
- } else {
- st->pts += 65535 + dhav->timestamp - st->last_timestamp;
- }
-
- st->last_timestamp = dhav->timestamp;
-
- return st->pts;
-}
-
static const uint32_t sample_rates[] = {
8000, 4000, 8000, 11025, 16000,
20000, 22050, 32000, 44100, 48000,
@@ -264,15 +195,15 @@ static int read_chunk(AVFormatContext *s)
dhav->frame_subnumber = avio_r8(s->pb);
dhav->frame_number = avio_rl32(s->pb);
frame_length = avio_rl32(s->pb);
+ dhav->date = avio_rl32(s->pb);
if (frame_length < 24)
return AVERROR_INVALIDDATA;
if (dhav->type == 0xf1) {
- ret = avio_skip(s->pb, frame_length - 16);
+ ret = avio_skip(s->pb, frame_length - 20);
return ret < 0 ? ret : 0;
}
- dhav->date = avio_rl32(s->pb);
dhav->timestamp = avio_rl16(s->pb);
ext_length = avio_r8(s->pb);
avio_skip(s->pb, 1); // checksum
@@ -286,10 +217,125 @@ static int read_chunk(AVFormatContext *s)
return frame_length - 8 - (end - start);
}
+static void get_timeinfo(unsigned date, struct tm *timeinfo)
+{
+ int year, month, day, hour, min, sec;
+
+ sec = date & 0x3F;
+ min = (date >> 6) & 0x3F;
+ hour = (date >> 12) & 0x1F;
+ day = (date >> 17) & 0x1F;
+ month = (date >> 22) & 0x0F;
+ year = ((date >> 26) & 0x3F) + 2000;
+
+ timeinfo->tm_year = year - 1900;
+ timeinfo->tm_mon = month - 1;
+ timeinfo->tm_mday = day;
+ timeinfo->tm_hour = hour;
+ timeinfo->tm_min = min;
+ timeinfo->tm_sec = sec;
+}
+
+static int64_t get_duration(AVFormatContext *s)
+{
+ DHAVContext *dhav = s->priv_data;
+ int64_t start_pos = avio_tell(s->pb);
+ int64_t start = 0, end = 0;
+ struct tm timeinfo;
+
+ if (!s->pb->seekable)
+ return 0;
+
+ avio_seek(s->pb, avio_size(s->pb) - 8, SEEK_SET);
+ if (avio_rl32(s->pb) == MKTAG('d','h','a','v')) {
+ int seek_back = avio_rl32(s->pb);
+
+ avio_seek(s->pb, -seek_back, SEEK_CUR);
+ read_chunk(s);
+ get_timeinfo(dhav->date, &timeinfo);
+ end = av_timegm(&timeinfo) * 1000LL;
+ } else {
+ avio_seek(s->pb, start_pos, SEEK_SET);
+ return 0;
+ }
+
+ avio_seek(s->pb, start_pos, SEEK_SET);
+
+ read_chunk(s);
+ get_timeinfo(dhav->date, &timeinfo);
+ start = av_timegm(&timeinfo) * 1000LL;
+
+ avio_seek(s->pb, start_pos, SEEK_SET);
+
+ return end - start;
+}
+
+static int dhav_read_header(AVFormatContext *s)
+{
+ DHAVContext *dhav = s->priv_data;
+ uint8_t signature[5];
+
+ ffio_ensure_seekback(s->pb, 5);
+ avio_read(s->pb, signature, sizeof(signature));
+ if (!memcmp(signature, "DAHUA", 5)) {
+ avio_skip(s->pb, 0x400 - 5);
+ dhav->last_good_pos = avio_tell(s->pb);
+ } else {
+ if (!memcmp(signature, "DHAV", 4)) {
+ avio_seek(s->pb, -5, SEEK_CUR);
+ dhav->last_good_pos = avio_tell(s->pb);
+ } else if (s->pb->seekable) {
+ avio_seek(s->pb, avio_size(s->pb) - 8, SEEK_SET);
+ while (avio_rl32(s->pb) == MKTAG('d','h','a','v')) {
+ int seek_back;
+
+ seek_back = avio_rl32(s->pb) + 8;
+ dhav->last_good_pos = avio_tell(s->pb);
+ avio_seek(s->pb, -seek_back, SEEK_CUR);
+ }
+ avio_seek(s->pb, dhav->last_good_pos, SEEK_SET);
+ }
+ }
+
+ dhav->duration = get_duration(s);
+ dhav->last_good_pos = avio_tell(s->pb);
+ s->ctx_flags |= AVFMTCTX_NOHEADER;
+ dhav->video_stream_index = -1;
+ dhav->audio_stream_index = -1;
+
+ return 0;
+}
+
+static int64_t get_pts(AVFormatContext *s, int stream_index)
+{
+ DHAVStream *dst = s->streams[stream_index]->priv_data;
+ DHAVContext *dhav = s->priv_data;
+ struct tm timeinfo;
+ time_t t;
+
+ get_timeinfo(dhav->date, &timeinfo);
+
+ t = av_timegm(&timeinfo);
+ if (dst->last_time == t) {
+ int64_t diff = dhav->timestamp - dst->last_timestamp;
+
+ if (diff < 0)
+ diff += 65535;
+ dst->pts += diff;
+ } else {
+ dst->pts = t * 1000LL;
+ }
+
+ dst->last_time = t;
+ dst->last_timestamp = dhav->timestamp;
+
+ return dst->pts;
+}
+
static int dhav_read_packet(AVFormatContext *s, AVPacket *pkt)
{
DHAVContext *dhav = s->priv_data;
- int ret, stream_index;
+ int size, ret, stream_index;
retry:
while ((ret = read_chunk(s)) == 0)
@@ -315,6 +361,7 @@ retry:
case 0xc: st->codecpar->codec_id = AV_CODEC_ID_HEVC; break;
default: avpriv_request_sample(s, "Unknown video codec %X\n", dhav->video_codec);
}
+ st->duration = dhav->duration;
st->codecpar->width = dhav->width;
st->codecpar->height = dhav->height;
st->avg_frame_rate.num = dhav->frame_rate;
@@ -322,7 +369,7 @@ retry:
st->priv_data = dst = av_mallocz(sizeof(DHAVStream));
if (!st->priv_data)
return AVERROR(ENOMEM);
- dst->last_timestamp = AV_NOPTS_VALUE;
+ dst->last_time = AV_NOPTS_VALUE;
dhav->video_stream_index = st->index;
avpriv_set_pts_info(st, 64, 1, 1000);
@@ -347,12 +394,13 @@ retry:
case 0x0d: st->codecpar->codec_id = AV_CODEC_ID_ADPCM_MS; break;
default: avpriv_request_sample(s, "Unknown audio codec %X\n", dhav->audio_codec);
}
+ st->duration = dhav->duration;
st->codecpar->channels = dhav->audio_channels;
st->codecpar->sample_rate = dhav->sample_rate;
st->priv_data = dst = av_mallocz(sizeof(DHAVStream));
if (!st->priv_data)
return AVERROR(ENOMEM);
- dst->last_timestamp = AV_NOPTS_VALUE;
+ dst->last_time = AV_NOPTS_VALUE;
dhav->audio_stream_index = st->index;
avpriv_set_pts_info(st, 64, 1, 1000);
@@ -366,15 +414,16 @@ retry:
goto retry;
}
- ret = av_get_packet(s->pb, pkt, ret);
+ size = ret;
+ ret = av_get_packet(s->pb, pkt, size);
if (ret < 0)
return ret;
pkt->stream_index = stream_index;
if (dhav->type != 0xfc)
pkt->flags |= AV_PKT_FLAG_KEY;
- if (pkt->stream_index >= 0)
- pkt->pts = get_pts(s, s->streams[pkt->stream_index]->priv_data);
pkt->duration = 1;
+ if (pkt->stream_index >= 0)
+ pkt->pts = get_pts(s, pkt->stream_index);
pkt->pos = dhav->last_good_pos;
if (avio_rl32(s->pb) == MKTAG('d','h','a','v'))
avio_skip(s->pb, 4);
@@ -402,7 +451,7 @@ static int dhav_read_seek(AVFormatContext *s, int stream_index,
DHAVStream *dst = st->priv_data;
dst->pts = pts;
- dst->last_timestamp = AV_NOPTS_VALUE;
+ dst->last_time = AV_NOPTS_VALUE;
}
dhav->last_good_pos = avio_tell(s->pb);
@@ -418,5 +467,5 @@ AVInputFormat ff_dhav_demuxer = {
.read_packet = dhav_read_packet,
.read_seek = dhav_read_seek,
.extensions = "dav",
- .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK,
+ .flags = AVFMT_GENERIC_INDEX | AVFMT_NO_BYTE_SEEK | AVFMT_TS_DISCONT | AVFMT_TS_NONSTRICT,
};