From af35a13f6d269a2400fd36ecc70b74ea2da1f1a8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Ekstr=C3=B6m?= Date: Mon, 22 Nov 2021 14:07:04 +0200 Subject: [PATCH] avformat/movenc: add support for fragmented TTML muxing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Attempts to base the fragmentation timing on other streams as most receivers expect media fragments to be more or less aligned. Currently does not support fragmentation on subtitle track only, as the subtitle packet queue timings would have to be checked in addition to the current fragmentation timing logic. Signed-off-by: Jan Ekström --- libavformat/movenc.c | 9 - libavformat/movenc_ttml.c | 155 ++++++- libavformat/version.h | 2 +- tests/fate/mov.mak | 21 + tests/ref/fate/mov-mp4-fragmented-ttml-dfxp | 430 ++++++++++++++++++++ tests/ref/fate/mov-mp4-fragmented-ttml-stpp | 430 ++++++++++++++++++++ 6 files changed, 1033 insertions(+), 14 deletions(-) create mode 100644 tests/ref/fate/mov-mp4-fragmented-ttml-dfxp create mode 100644 tests/ref/fate/mov-mp4-fragmented-ttml-stpp diff --git a/libavformat/movenc.c b/libavformat/movenc.c index e67a14a7d6..bfe76a2034 100644 --- a/libavformat/movenc.c +++ b/libavformat/movenc.c @@ -8254,15 +8254,6 @@ static int mov_init(AVFormatContext *s) track->squash_fragment_samples_to_one = ff_is_ttml_stream_paragraph_based(track->par); - if (mov->flags & FF_MOV_FLAG_FRAGMENT && - track->squash_fragment_samples_to_one) { - av_log(s, AV_LOG_ERROR, - "Fragmentation is not currently supported for " - "TTML in MP4/ISMV (track synchronization between " - "subtitles and other media is not yet implemented)!\n"); - return AVERROR_PATCHWELCOME; - } - if (track->mode != MODE_ISM && track->par->codec_tag == MOV_ISMV_TTML_TAG && s->strict_std_compliance > FF_COMPLIANCE_UNOFFICIAL) { diff --git a/libavformat/movenc_ttml.c b/libavformat/movenc_ttml.c index 413eccfc0f..c5232e589c 100644 --- a/libavformat/movenc_ttml.c +++ b/libavformat/movenc_ttml.c @@ -55,6 +55,48 @@ static int mov_init_ttml_writer(MOVTrack *track, AVFormatContext **out_ctx) return 0; } +static void mov_calculate_start_and_end_of_other_tracks( + AVFormatContext *s, MOVTrack *track, int64_t *start_pts, int64_t *end_pts) +{ + MOVMuxContext *mov = s->priv_data; + + // Initialize at the end of the previous document/fragment, which is NOPTS + // until the first fragment is created. + int64_t max_track_end_dts = *start_pts = track->end_pts; + + for (unsigned int i = 0; i < s->nb_streams; i++) { + MOVTrack *other_track = &mov->tracks[i]; + + // Skip our own track, any other track that needs squashing, + // or any track which still has its start_dts at NOPTS or + // any track that did not yet get any packets. + if (track == other_track || + other_track->squash_fragment_samples_to_one || + other_track->start_dts == AV_NOPTS_VALUE || + !other_track->entry) { + continue; + } + + int64_t picked_start = av_rescale_q_rnd(other_track->cluster[0].dts + other_track->cluster[0].cts, + other_track->st->time_base, + track->st->time_base, + AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); + int64_t picked_end = av_rescale_q_rnd(other_track->end_pts, + other_track->st->time_base, + track->st->time_base, + AV_ROUND_NEAR_INF | AV_ROUND_PASS_MINMAX); + + if (*start_pts == AV_NOPTS_VALUE) + *start_pts = picked_start; + else if (picked_start >= track->end_pts) + *start_pts = FFMIN(*start_pts, picked_start); + + max_track_end_dts = FFMAX(max_track_end_dts, picked_end); + } + + *end_pts = max_track_end_dts; +} + static int mov_write_ttml_document_from_queue(AVFormatContext *s, AVFormatContext *ttml_ctx, MOVTrack *track, @@ -66,13 +108,85 @@ static int mov_write_ttml_document_from_queue(AVFormatContext *s, int64_t start_ts = track->start_dts == AV_NOPTS_VALUE ? 0 : (track->start_dts + track->track_duration); int64_t end_ts = start_ts; + unsigned int time_limited = 0; + PacketList back_to_queue_list = { 0 }; + + if (*out_start_ts != AV_NOPTS_VALUE) { + // we have non-nopts values here, thus we have been given a time range + time_limited = 1; + start_ts = *out_start_ts; + end_ts = *out_start_ts + *out_duration; + } if ((ret = avformat_write_header(ttml_ctx, NULL)) < 0) { return ret; } while (!avpriv_packet_list_get(&track->squashed_packet_queue, pkt)) { - end_ts = FFMAX(end_ts, pkt->pts + pkt->duration); + int64_t pts_before = pkt->pts; + int64_t duration_before = pkt->duration; + + if (time_limited) { + // special cases first: + if (pkt->pts + pkt->duration < start_ts) { + // too late for our fragment, unfortunately + // unref and proceed to next packet in queue. + av_log(s, AV_LOG_WARNING, + "Very late TTML packet in queue, dropping packet with " + "pts: %"PRId64", duration: %"PRId64"\n", + pkt->pts, pkt->duration); + av_packet_unref(pkt); + continue; + } else if (pkt->pts >= end_ts) { + // starts after this fragment, put back to original queue + ret = avpriv_packet_list_put(&track->squashed_packet_queue, + pkt, av_packet_ref, + FF_PACKETLIST_FLAG_PREPEND); + if (ret < 0) + goto cleanup; + + break; + } + + // limit packet pts to start_ts + if (pkt->pts < start_ts) { + pkt->duration -= start_ts - pkt->pts; + pkt->pts = start_ts; + } + + if (pkt->pts + pkt->duration > end_ts) { + // goes over our current fragment, create duplicate and + // put it back to list after iteration has finished in + // order to handle multiple subtitles at the same time. + int64_t offset = end_ts - pkt->pts; + + ret = avpriv_packet_list_put(&back_to_queue_list, + pkt, av_packet_ref, + FF_PACKETLIST_FLAG_PREPEND); + if (ret < 0) + goto cleanup; + + back_to_queue_list.head->pkt.pts = + back_to_queue_list.head->pkt.dts = + back_to_queue_list.head->pkt.pts + offset; + back_to_queue_list.head->pkt.duration -= offset; + + // and for our normal packet we just set duration to offset + pkt->duration = offset; + } + } else { + end_ts = FFMAX(end_ts, pkt->pts + pkt->duration); + } + + av_log(s, AV_LOG_TRACE, + "TTML packet writeout: pts: %"PRId64" (%"PRId64"), " + "duration: %"PRId64"\n", + pkt->pts, pkt->pts - start_ts, pkt->duration); + if (pkt->pts != pts_before || pkt->duration != duration_before) { + av_log(s, AV_LOG_TRACE, + "Adjustments: pts: %"PRId64", duration: %"PRId64"\n", + pkt->pts - pts_before, pkt->duration - duration_before); + } // in case of the 'dfxp' muxing mode, each written document is offset // to its containing sample's beginning. @@ -101,15 +215,30 @@ static int mov_write_ttml_document_from_queue(AVFormatContext *s, ret = 0; cleanup: + while (!avpriv_packet_list_get(&back_to_queue_list, pkt)) { + ret = avpriv_packet_list_put(&track->squashed_packet_queue, + pkt, av_packet_ref, + FF_PACKETLIST_FLAG_PREPEND); + + // unrelated to whether we succeed or not, we unref the packet + // received from the temporary list. + av_packet_unref(pkt); + + if (ret < 0) { + avpriv_packet_list_free(&back_to_queue_list); + break; + } + } return ret; } int ff_mov_generate_squashed_ttml_packet(AVFormatContext *s, MOVTrack *track, AVPacket *pkt) { + MOVMuxContext *mov = s->priv_data; AVFormatContext *ttml_ctx = NULL; // values for the generated AVPacket - int64_t start_ts = 0; + int64_t start_ts = AV_NOPTS_VALUE; int64_t duration = 0; int ret = AVERROR_BUG; @@ -120,12 +249,30 @@ int ff_mov_generate_squashed_ttml_packet(AVFormatContext *s, goto cleanup; } + if (mov->flags & FF_MOV_FLAG_FRAGMENT) { + int64_t calculated_start = AV_NOPTS_VALUE; + int64_t calculated_end = AV_NOPTS_VALUE; + + mov_calculate_start_and_end_of_other_tracks(s, track, &calculated_start, &calculated_end); + + if (calculated_start != AV_NOPTS_VALUE) { + start_ts = calculated_start; + duration = calculated_end - calculated_start; + av_log(s, AV_LOG_VERBOSE, + "Calculated subtitle fragment start: %"PRId64", " + "duration: %"PRId64"\n", + start_ts, duration); + } + } + if (!track->squashed_packet_queue.head) { // empty queue, write minimal empty document with zero duration avio_write(ttml_ctx->pb, empty_ttml_document, sizeof(empty_ttml_document) - 1); - start_ts = 0; - duration = 0; + if (start_ts == AV_NOPTS_VALUE) { + start_ts = 0; + duration = 0; + } goto generate_packet; } diff --git a/libavformat/version.h b/libavformat/version.h index e2634b85ae..384cbd49cc 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -32,7 +32,7 @@ #include "version_major.h" #define LIBAVFORMAT_VERSION_MINOR 5 -#define LIBAVFORMAT_VERSION_MICRO 100 +#define LIBAVFORMAT_VERSION_MICRO 101 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \ LIBAVFORMAT_VERSION_MINOR, \ diff --git a/tests/fate/mov.mak b/tests/fate/mov.mak index c43f260dd3..eb666c5865 100644 --- a/tests/fate/mov.mak +++ b/tests/fate/mov.mak @@ -158,6 +158,27 @@ FATE_MOV_FFMPEG_FFPROBE_SAMPLES-$(call TRANSCODE, TTML SUBRIP, MP4 MOV, SRT_DEMU fate-mov-mp4-ttml-stpp: CMD = transcode srt $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt mp4 "-map 0:s -c:s ttml -time_base:s 1:1000" "-map 0 -c copy" "-of json -show_entries packet:stream=index,codec_type,codec_tag_string,codec_tag,codec_name,time_base,start_time,duration_ts,duration,nb_frames,nb_read_packets:stream_tags" fate-mov-mp4-ttml-dfxp: CMD = transcode srt $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt mp4 "-map 0:s -c:s ttml -time_base:s 1:1000 -tag:s dfxp -strict unofficial" "-map 0 -c copy" "-of json -show_entries packet:stream=index,codec_type,codec_tag_string,codec_tag,codec_name,time_base,start_time,duration_ts,duration,nb_frames,nb_read_packets:stream_tags" +FATE_MOV_FFMPEG_FFPROBE_SAMPLES-$(call TRANSCODE, TTML SUBRIP, MP4 MOV, LAVFI_INDEV SMPTEHDBARS_FILTER SRT_DEMUXER MPEG2VIDEO_ENCODER TTML_MUXER RAWVIDEO_MUXER) += fate-mov-mp4-fragmented-ttml-stpp +fate-mov-mp4-fragmented-ttml-stpp: CMD = transcode srt $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt mp4 \ + "-map 1:v -map 0:s \ + -c:v mpeg2video -b:v 2M -g 48 -sc_threshold 1000000000 \ + -c:s ttml -time_base:s 1:1000 \ + -movflags +cmaf" \ + "-map 0:s -c copy" \ + "-select_streams s -of csv -show_packets -show_data_hash crc32" \ + "-f lavfi -i smptehdbars=duration=24.5245:size=320x180:rate=24000/1001,format=yuv420p" \ + "" "" "data" + +FATE_MOV_FFMPEG_FFPROBE_SAMPLES-$(call TRANSCODE, TTML SUBRIP, ISMV MOV, LAVFI_INDEV SMPTEHDBARS_FILTER SRT_DEMUXER MPEG2VIDEO_ENCODER TTML_MUXER RAWVIDEO_MUXER) += fate-mov-mp4-fragmented-ttml-dfxp +fate-mov-mp4-fragmented-ttml-dfxp: CMD = transcode srt $(TARGET_SAMPLES)/sub/SubRip_capability_tester.srt ismv \ + "-map 1:v -map 0:s \ + -c:v mpeg2video -b:v 2M -g 48 -sc_threshold 1000000000 \ + -c:s ttml -tag:s dfxp -time_base:s 1:1000" \ + "-map 0:s -c copy" \ + "-select_streams s -of csv -show_packets -show_data_hash crc32" \ + "-f lavfi -i smptehdbars=duration=24.5245:size=320x180:rate=24000/1001,format=yuv420p" \ + "" "" "data" + # avif demuxing - still image with 1 item. FATE_MOV_FFMPEG_SAMPLES-$(call FRAMECRC, MOV, AV1, AV1_PARSER) \ += fate-mov-avif-demux-still-image-1-item diff --git a/tests/ref/fate/mov-mp4-fragmented-ttml-dfxp b/tests/ref/fate/mov-mp4-fragmented-ttml-dfxp new file mode 100644 index 0000000000..ee1189cebf --- /dev/null +++ b/tests/ref/fate/mov-mp4-fragmented-ttml-dfxp @@ -0,0 +1,430 @@ +09836de7062020ab760fc949875b7e2b *tests/data/fate/mov-mp4-fragmented-ttml-dfxp.ismv +189404 tests/data/fate/mov-mp4-fragmented-ttml-dfxp.ismv + + + + + + + + +
+

Don't show this text it may be used to insert hidden data

+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+
+ +
+ + + + + + + + +
+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+
+ +
+ + + + + + + + +
+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+

Hidden

+

This text should be small
This text should be normal
This text should be big

+
+ +
+ + + + + + + + +
+

This text should be small
This text should be normal
This text should be big

+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+
+ +
+ + + + + + + + +
+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+
+ +
+ + + + + + + + +
+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+
+ +
+ + + + + + + + +
+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+
+ +
+ + + + + + + + +
+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+

>
It would be a good thing to
hide invalid html tags that are closed and show the text in them
but show un-closed invalid html tags
Show not opened tags
<

+
+ +
+ + + + + + + + +
+

>
It would be a good thing to
hide invalid html tags that are closed and show the text in them
but show un-closed invalid html tags
Show not opened tags
<

+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+
+ +
+ + + + + + + + +
+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+
+ +
+ + + + + + + + +
+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+

This text should be in the normal position...

+

This text should NOT be in the normal position

+
+ +
+ + + + + + + + +
+

This text should NOT be in the normal position

+

Implementation is the same of the ASS tag
This text should be at the
top and horizontally centered

+

This text should be at the
middle and horizontally centered

+

This text should be at the
bottom and horizontally centered

+
+ +
+ + + + + + + + +
+

Implementation is the same of the ASS tag
This text should be at the
top and horizontally centered

+

This text should be at the
middle and horizontally centered

+

This text should be at the
bottom and horizontally centered

+

This text should be at the
top and horizontally at the left

+

This text should be at the
middle and horizontally at the left
(The second position must be ignored)

+

This text should be at the
bottom and horizontally at the left

+
+ +
+packet,subtitle,1,0,0.000000,0,0.000000,20020000,2.002000,1172,14746,K__,CRC32:bde7afa1 +packet,subtitle,1,20020000,2.002000,20020000,2.002000,20020000,2.002000,1015,29540,K__,CRC32:c1cb78f2 +packet,subtitle,1,40040000,4.004000,40040000,4.004000,20020000,2.002000,1305,44177,K__,CRC32:267b17fe +packet,subtitle,1,60060000,6.006000,60060000,6.006000,20020000,2.002000,1111,59104,K__,CRC32:d6aaf284 +packet,subtitle,1,80080000,8.008000,80080000,8.008000,20020000,2.002000,927,73837,K__,CRC32:0ee24ad7 +packet,subtitle,1,100100000,10.010000,100100000,10.010000,20020000,2.002000,1194,88386,K__,CRC32:a9816515 +packet,subtitle,1,120120000,12.012000,120120000,12.012000,20020000,2.002000,874,103202,K__,CRC32:c47ebb4e +packet,subtitle,1,140140000,14.014000,140140000,14.014000,20020000,2.002000,1154,117698,K__,CRC32:09b26179 +packet,subtitle,1,160160000,16.016000,160160000,16.016000,20020000,2.002000,1240,132474,K__,CRC32:d7e3067e +packet,subtitle,1,180180000,18.018000,180180000,18.018000,20020000,2.002000,960,147336,K__,CRC32:d2d99797 +packet,subtitle,1,200200000,20.020000,200200000,20.020000,20020000,2.002000,1251,161918,K__,CRC32:1857892c +packet,subtitle,1,220220000,22.022000,220220000,22.022000,20020000,2.002000,1285,176791,K__,CRC32:76bd9787 +packet,subtitle,1,240240000,24.024000,240240000,24.024000,5005000,0.500500,1676,187162,K__,CRC32:b519ec6f diff --git a/tests/ref/fate/mov-mp4-fragmented-ttml-stpp b/tests/ref/fate/mov-mp4-fragmented-ttml-stpp new file mode 100644 index 0000000000..3e3371afad --- /dev/null +++ b/tests/ref/fate/mov-mp4-fragmented-ttml-stpp @@ -0,0 +1,430 @@ +d7c6570fbe8c1ec630c2f1639ae16fcb *tests/data/fate/mov-mp4-fragmented-ttml-stpp.mp4 +183872 tests/data/fate/mov-mp4-fragmented-ttml-stpp.mp4 + + + + + + + + +
+

Don't show this text it may be used to insert hidden data

+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+
+ +
+ + + + + + + + +
+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+
+ +
+ + + + + + + + +
+

SubRip subtitles capability tester 1.3o by ale5000
Use VLC 1.1 or higher as reference for most things and MPC Home Cinema for others
This text should be blue
This text should be red
This text should be black
If you see this with the normal font, the player don't (fully) support font face

+

Hidden

+

This text should be small
This text should be normal
This text should be big

+
+ +
+ + + + + + + + +
+

This text should be small
This text should be normal
This text should be big

+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+
+ +
+ + + + + + + + +
+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+
+ +
+ + + + + + + + +
+

This should be an E with an accent: È
日本語
This text should be bold, italics and underline
This text should be small and green
This text should be small and red
This text should be big and brown

+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+
+ +
+ + + + + + + + +
+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+
+ +
+ + + + + + + + +
+

This line should be bold
This line should be italics
This line should be underline
This line should be strikethrough
Both lines
should be underline

+

>
It would be a good thing to
hide invalid html tags that are closed and show the text in them
but show un-closed invalid html tags
Show not opened tags
<

+
+ +
+ + + + + + + + +
+

>
It would be a good thing to
hide invalid html tags that are closed and show the text in them
but show un-closed invalid html tags
Show not opened tags
<

+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+
+ +
+ + + + + + + + +
+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+
+ +
+ + + + + + + + +
+

and also
hide invalid html tags with parameters that are closed and show the text in them
but show un-closed invalid html tags
This text should be showed underlined without problems also: 2<3,5>1,4<6
This shouldn't be underlined

+

This text should be in the normal position...

+

This text should NOT be in the normal position

+
+ +
+ + + + + + + + +
+

This text should NOT be in the normal position

+

Implementation is the same of the ASS tag
This text should be at the
top and horizontally centered

+

This text should be at the
middle and horizontally centered

+

This text should be at the
bottom and horizontally centered

+
+ +
+ + + + + + + + +
+

Implementation is the same of the ASS tag
This text should be at the
top and horizontally centered

+

This text should be at the
middle and horizontally centered

+

This text should be at the
bottom and horizontally centered

+

This text should be at the
top and horizontally at the left

+

This text should be at the
middle and horizontally at the left
(The second position must be ignored)

+

This text should be at the
bottom and horizontally at the left

+
+ +
+packet,subtitle,1,0,0.000000,0,0.000000,2002,2.002000,1172,14302,K__,CRC32:bde7afa1 +packet,subtitle,1,2002,2.002000,2002,2.002000,2002,2.002000,1015,28648,K__,CRC32:bd3bd4bc +packet,subtitle,1,4004,4.004000,4004,4.004000,2002,2.002000,1305,42837,K__,CRC32:c8ff5017 +packet,subtitle,1,6006,6.006000,6006,6.006000,2002,2.002000,1111,57316,K__,CRC32:f0b10da6 +packet,subtitle,1,8008,8.008000,8008,8.008000,2002,2.002000,927,71601,K__,CRC32:55a7bb1b +packet,subtitle,1,10010,10.010000,10010,10.010000,2002,2.002000,1194,85702,K__,CRC32:03dc4753 +packet,subtitle,1,12012,12.012000,12012,12.012000,2002,2.002000,874,100070,K__,CRC32:c7a092d4 +packet,subtitle,1,14014,14.014000,14014,14.014000,2002,2.002000,1154,114118,K__,CRC32:b476fe9c +packet,subtitle,1,16016,16.016000,16016,16.016000,2002,2.002000,1240,128446,K__,CRC32:912e694c +packet,subtitle,1,18018,18.018000,18018,18.018000,2002,2.002000,960,142860,K__,CRC32:bba73912 +packet,subtitle,1,20020,20.020000,20020,20.020000,2002,2.002000,1251,156994,K__,CRC32:4c7b87d8 +packet,subtitle,1,22022,22.022000,22022,22.022000,2002,2.002000,1285,171419,K__,CRC32:c0368927 +packet,subtitle,1,24024,24.024000,24024,24.024000,501,0.501000,1676,181630,K__,CRC32:812a103f