Skip to content

Commit 9e8926f

Browse files
authored
Add TrackFileResource EntryPoint, Duration and Repeat parameters support (#32) (#29)
2 parents 2422678 + de96d11 commit 9e8926f

File tree

2 files changed

+66
-30
lines changed

2 files changed

+66
-30
lines changed

libavformat/imf_internal.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,8 @@
3939
#include <libxml/tree.h>
4040

4141
#define UUID_FORMAT "urn:uuid:%02hhx%02hhx%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx-%02hhx%02hhx%02hhx%02hhx%02hhx%02hhx"
42+
#define AVRATIONAL_FORMAT "%d/%d"
43+
#define AVRATIONAL_ARG(rational) rational.num, rational.den
4244

4345
/**
4446
* IMF Asset locator

libavformat/imfdec.c

Lines changed: 64 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,13 @@ typedef struct IMFVirtualTrackPlaybackCtx {
6363
// Track index in playlist
6464
int32_t index;
6565
// Time counters
66-
int64_t current_timestamp;
67-
int64_t duration;
66+
AVRational current_timestamp;
67+
AVRational duration;
6868
// Resources
6969
unsigned int resource_count;
7070
IMFVirtualTrackResourcePlaybackCtx **resources;
7171
// Decoding cursors
72-
IMFVirtualTrackResourcePlaybackCtx *current_resource;
72+
uint32_t current_resource_index;
7373
int64_t last_pts;
7474
} IMFVirtualTrackPlaybackCtx;
7575

@@ -185,9 +185,9 @@ static int parse_assetmap(AVFormatContext *s, const char *url, AVIOContext *in)
185185
AVDictionary *opts = NULL;
186186
xmlDoc *doc = NULL;
187187

188-
int close_in = 0;
189-
int ret = 0;
190-
int64_t filesize = 0;
188+
int close_in;
189+
int ret;
190+
int64_t filesize;
191191

192192
const char *base_url = av_dirname(strdup(url));
193193
if (c->asset_locator_map == NULL) {
@@ -253,6 +253,7 @@ static IMFAssetLocator *find_asset_map_locator(IMFAssetLocatorMap *asset_map, UU
253253

254254
static int open_track_resource_context(AVFormatContext *s, IMFVirtualTrackResourcePlaybackCtx *track_resource) {
255255
int ret = 0;
256+
int64_t entry_point;
256257

257258
if (!track_resource->ctx) {
258259
track_resource->ctx = avformat_alloc_context();
@@ -275,6 +276,22 @@ static int open_track_resource_context(AVFormatContext *s, IMFVirtualTrackResour
275276
goto cleanup;
276277
}
277278

279+
// Compare the source timebase to the resource edit rate, considering the first stream of the source file
280+
if (av_cmp_q(track_resource->ctx->streams[0]->time_base, av_inv_q(track_resource->resource->base.edit_rate))) {
281+
av_log(s, AV_LOG_WARNING, "Incoherent source stream timebase %d/%d regarding resource edit rate: %d/%d", track_resource->ctx->streams[0]->time_base.num, track_resource->ctx->streams[0]->time_base.den, track_resource->resource->base.edit_rate.den, track_resource->resource->base.edit_rate.num);
282+
}
283+
284+
entry_point = (int64_t)track_resource->resource->base.entry_point * track_resource->resource->base.edit_rate.den * AV_TIME_BASE / track_resource->resource->base.edit_rate.num;
285+
286+
if (entry_point) {
287+
av_log(s, AV_LOG_DEBUG, "Seek at resource %s entry point: %ld\n", track_resource->locator->absolute_uri, track_resource->resource->base.entry_point);
288+
ret = avformat_seek_file(track_resource->ctx, -1, entry_point, entry_point, entry_point, 0);
289+
if (ret < 0) {
290+
av_log(s, AV_LOG_ERROR, "Could not seek at %ld on %s: %s\n", entry_point, track_resource->locator->absolute_uri, av_err2str(ret));
291+
goto cleanup;
292+
}
293+
}
294+
278295
return ret;
279296
cleanup:
280297
avformat_free_context(track_resource->ctx);
@@ -286,7 +303,7 @@ static int open_track_file_resource(AVFormatContext *s, IMFTrackFileResource *tr
286303
IMFVirtualTrackResourcePlaybackCtx *track_resource;
287304
IMFAssetLocator *asset_locator;
288305

289-
int ret = 0;
306+
int ret;
290307

291308
if (!(asset_locator = find_asset_map_locator(c->asset_locator_map, track_file_resource->track_file_uuid))) {
292309
av_log(s, AV_LOG_ERROR, "Could not find asset locator for UUID: " UUID_FORMAT "\n", UID_ARG(track_file_resource->track_file_uuid));
@@ -303,9 +320,11 @@ static int open_track_file_resource(AVFormatContext *s, IMFTrackFileResource *tr
303320
return ret;
304321
}
305322

306-
track->resources = av_realloc(track->resources, track->resource_count + 1 * sizeof(IMFVirtualTrackResourcePlaybackCtx));
307-
track->resources[track->resource_count++] = track_resource;
308-
track->duration += track_resource->ctx->duration;
323+
for (int repetition = 0; repetition < track_file_resource->base.repeat_count; ++repetition) {
324+
track->resources = av_realloc(track->resources, (track->resource_count + 1) * sizeof(IMFVirtualTrackResourcePlaybackCtx));
325+
track->resources[track->resource_count++] = track_resource;
326+
track->duration = av_add_q(track->duration, av_make_q((int)track_resource->resource->base.duration * track_resource->resource->base.edit_rate.den, track_resource->resource->base.edit_rate.num));
327+
}
309328

310329
return ret;
311330
}
@@ -317,6 +336,7 @@ static int open_virtual_track(AVFormatContext *s, IMFTrackFileVirtualTrack *virt
317336

318337
track = av_mallocz(sizeof(IMFVirtualTrackPlaybackCtx));
319338
track->index = track_index;
339+
track->duration = av_make_q(0, INT32_MAX);
320340

321341
for (int i = 0; i < virtual_track->resource_count; i++) {
322342
av_log(s, AV_LOG_DEBUG, "Open stream from file " UUID_FORMAT ", stream %d\n", UID_ARG(virtual_track->resources[i].track_file_uuid), i);
@@ -326,7 +346,9 @@ static int open_virtual_track(AVFormatContext *s, IMFTrackFileVirtualTrack *virt
326346
}
327347
}
328348

329-
c->tracks = av_realloc(c->tracks, c->track_count + 1 * sizeof(IMFVirtualTrackPlaybackCtx));
349+
track->current_timestamp = av_make_q(0, track->duration.den);
350+
351+
c->tracks = av_realloc(c->tracks, (c->track_count + 1) * sizeof(IMFVirtualTrackPlaybackCtx));
330352
c->tracks[c->track_count++] = track;
331353

332354
return ret;
@@ -344,6 +366,7 @@ static void imf_virtual_track_playback_context_free(IMFVirtualTrackPlaybackCtx *
344366

345367
if (track->resources[i]->ctx && track->resources[i]->ctx->iformat) {
346368
avformat_free_context(track->resources[i]->ctx);
369+
track->resources[i]->ctx = NULL;
347370
}
348371
}
349372
}
@@ -370,6 +393,7 @@ static int set_context_streams_from_tracks(AVFormatContext *s) {
370393
break;
371394
}
372395
avpriv_set_pts_info(asset_stream, first_resource_stream->pts_wrap_bits, first_resource_stream->time_base.num, first_resource_stream->time_base.den);
396+
asset_stream->duration = (int64_t)av_q2d(av_mul_q(c->tracks[i]->duration, av_inv_q(asset_stream->time_base)));
373397
}
374398

375399
return ret;
@@ -446,42 +470,41 @@ static IMFVirtualTrackPlaybackCtx *get_next_track_with_minimum_timestamp(AVForma
446470
IMFContext *c = s->priv_data;
447471
IMFVirtualTrackPlaybackCtx *track;
448472

449-
int64_t minimum_timestamp = INT64_MAX;
473+
AVRational minimum_timestamp = av_make_q(INT32_MAX, 1);
450474
for (int i = 0; i < c->track_count; ++i) {
451-
av_log(s, AV_LOG_DEBUG, "Compare track %p timestamp %ld to minimum %ld (over duration: %ld)\n", c->tracks[i], c->tracks[i]->current_timestamp, minimum_timestamp, c->tracks[i]->duration);
452-
if (c->tracks[i]->current_timestamp < minimum_timestamp) {
475+
av_log(s, AV_LOG_DEBUG, "Compare track %d timestamp " AVRATIONAL_FORMAT " to minimum " AVRATIONAL_FORMAT " (over duration: " AVRATIONAL_FORMAT ")\n", i, AVRATIONAL_ARG(c->tracks[i]->current_timestamp), AVRATIONAL_ARG(minimum_timestamp), AVRATIONAL_ARG(c->tracks[i]->duration));
476+
if (av_cmp_q(c->tracks[i]->current_timestamp, minimum_timestamp) < 0) {
453477
track = c->tracks[i];
454478
minimum_timestamp = track->current_timestamp;
455479
}
456480
}
457481

458-
av_log(s, AV_LOG_DEBUG, "Found next track to read: %d (timestamp: %ld / %ld)\n", track->index, track->current_timestamp, minimum_timestamp);
482+
av_log(s, AV_LOG_DEBUG, "Found next track to read: %d (timestamp: %lf / %lf)\n", track->index, av_q2d(track->current_timestamp), av_q2d(minimum_timestamp));
459483
return track;
460484
}
461485

462486
static IMFVirtualTrackResourcePlaybackCtx *get_resource_context_for_timestamp(AVFormatContext *s, IMFVirtualTrackPlaybackCtx *track) {
463-
unsigned long cumulated_duration = 0;
464-
unsigned long edit_unit_duration;
487+
AVRational edit_unit_duration = av_inv_q(track->resources[0]->resource->base.edit_rate);
488+
AVRational cumulated_duration = av_make_q(0, edit_unit_duration.den);
465489

466-
av_log(s, AV_LOG_DEBUG, "Looking for track %d resource for timestamp = %ld / %ld\n", track->index, track->current_timestamp, track->duration);
490+
av_log(s, AV_LOG_DEBUG, "Looking for track %d resource for timestamp = %lf / %lf\n", track->index, av_q2d(track->current_timestamp), av_q2d(track->duration));
467491
for (int i = 0; i < track->resource_count; ++i) {
468-
edit_unit_duration = track->resources[i]->resource->base.edit_rate.den * AV_TIME_BASE / track->resources[i]->resource->base.edit_rate.num;
469-
cumulated_duration += track->resources[i]->resource->base.duration * track->resources[i]->resource->base.edit_rate.den * AV_TIME_BASE / track->resources[i]->resource->base.edit_rate.num;
492+
cumulated_duration = av_add_q(cumulated_duration, av_make_q((int)track->resources[i]->resource->base.duration * edit_unit_duration.num, edit_unit_duration.den));
470493

471-
if (track->current_timestamp + edit_unit_duration <= cumulated_duration) {
472-
av_log(s, AV_LOG_DEBUG, "Found resource %d in track %d to read for timestamp %ld (on cumulated=%ld): entry=%ld, duration=%lu, editrate=%d/%d | edit_unit_duration=%ld\n", i, track->index, track->current_timestamp, cumulated_duration, track->resources[i]->resource->base.entry_point, track->resources[i]->resource->base.duration, track->resources[i]->resource->base.edit_rate.num, track->resources[i]->resource->base.edit_rate.den, edit_unit_duration);
494+
if (av_cmp_q(av_add_q(track->current_timestamp, edit_unit_duration), cumulated_duration) <= 0) {
495+
av_log(s, AV_LOG_DEBUG, "Found resource %d in track %d to read for timestamp %lf (on cumulated=%lf): entry=%ld, duration=%lu, editrate=" AVRATIONAL_FORMAT " | edit_unit_duration=%lf\n", i, track->index, av_q2d(track->current_timestamp), av_q2d(cumulated_duration), track->resources[i]->resource->base.entry_point, track->resources[i]->resource->base.duration, AVRATIONAL_ARG(track->resources[i]->resource->base.edit_rate), av_q2d(edit_unit_duration));
473496

474-
if (track->current_resource != track->resources[i]) {
497+
if (track->current_resource_index != i) {
475498
av_log(s, AV_LOG_DEBUG, "Switch resource on track %d: re-open context\n", track->index);
476-
if (track->current_resource != NULL) {
477-
avformat_close_input(&track->current_resource->ctx);
499+
if (track->resources[track->current_resource_index] != NULL) {
500+
avformat_close_input(&track->resources[track->current_resource_index]->ctx);
478501
}
479502
if (open_track_resource_context(s, track->resources[i]) != 0) {
480503
return NULL;
481504
}
482-
track->current_resource = track->resources[i];
505+
track->current_resource_index = i;
483506
}
484-
return track->current_resource;
507+
return track->resources[track->current_resource_index];
485508
}
486509
}
487510
return NULL;
@@ -491,31 +514,42 @@ static int ff_imf_read_packet(AVFormatContext *s, AVPacket *pkt) {
491514
IMFContext *c = s->priv_data;
492515

493516
IMFVirtualTrackResourcePlaybackCtx *resource_to_read = NULL;
517+
AVRational edit_unit_duration;
494518
int ret = 0;
495519

496520
IMFVirtualTrackPlaybackCtx *track_to_read = get_next_track_with_minimum_timestamp(s);
497521

498-
if (track_to_read->current_timestamp == track_to_read->duration) {
522+
if (av_cmp_q(track_to_read->current_timestamp, track_to_read->duration) == 0) {
499523
return AVERROR_EOF;
500524
}
501525

502526
resource_to_read = get_resource_context_for_timestamp(s, track_to_read);
503527

504528
if (!resource_to_read) {
529+
edit_unit_duration = av_inv_q(track_to_read->resources[track_to_read->current_resource_index]->resource->base.edit_rate);
530+
if (av_cmp_q(av_add_q(track_to_read->current_timestamp, edit_unit_duration), track_to_read->duration) > 0) {
531+
return AVERROR_EOF;
532+
}
533+
505534
av_log(s, AV_LOG_ERROR, "Could not find IMF track resource to read\n");
506535
return AVERROR_STREAM_NOT_FOUND;
507536
}
508537

509538
while (!ff_check_interrupt(c->interrupt_callback) && !ret) {
510539
ret = av_read_frame(resource_to_read->ctx, pkt);
511-
av_log(s, AV_LOG_DEBUG, "Got packet: pts=%ld, dts=%ld, duration=%ld, stream_index=%d, pos=%ld,\n", pkt->pts, pkt->dts, pkt->duration, pkt->stream_index, pkt->pos);
540+
av_log(s, AV_LOG_DEBUG, "Got packet: pts=%ld, dts=%ld, duration=%ld, stream_index=%d, pos=%ld\n", pkt->pts, pkt->dts, pkt->duration, pkt->stream_index, pkt->pos);
512541
if (ret >= 0) {
513542
// Update packet info from track
543+
if (pkt->dts < s->streams[track_to_read->index]->cur_dts && track_to_read->last_pts > 0) {
544+
pkt->dts = s->streams[track_to_read->index]->cur_dts;
545+
}
546+
514547
pkt->pts = track_to_read->last_pts;
548+
pkt->dts = pkt->dts - (int64_t)track_to_read->resources[track_to_read->current_resource_index]->resource->base.entry_point;
515549
pkt->stream_index = track_to_read->index;
516550

517551
// Update track cursors
518-
track_to_read->current_timestamp += av_rescale(pkt->duration, (int64_t)resource_to_read->ctx->streams[0]->time_base.num * AV_TIME_BASE, resource_to_read->ctx->streams[0]->time_base.den);
552+
track_to_read->current_timestamp = av_add_q(track_to_read->current_timestamp, av_make_q((int)pkt->duration * resource_to_read->ctx->streams[0]->time_base.num, resource_to_read->ctx->streams[0]->time_base.den));
519553
track_to_read->last_pts += pkt->duration;
520554

521555
return 0;

0 commit comments

Comments
 (0)