Re: [PATCH] demux: asf: Add support for TimeCode
Felix Paul Kühne <[email protected]> Mon, 21 Apr 2025 07:22:19 +0200
| Newsgroups | gmane.comp.video.videolan.vlc.devel |
|---|---|
| Message-ID | <[email protected]> |
Hello Ahmed, Thanks for your submission! We no longer accept contributions by patch through the mailing list. Please open a merge request on code.videolan.org <http://code.videolan.org/>. Best regards, Felix > On 21. Apr 2025, at 02:55, Ahmed Hamed <[email protected]> wrote: > > Support is added via payload extension and index object, timecode data is parsed and stored. > > --- > include/vlc_ancillary.h | 6 ++ > modules/demux/asf/asfpacket.c | 24 ++++++- > modules/demux/asf/asfpacket.h | 1 + > modules/demux/asf/libasf.c | 112 +++++++++++++++++++++++++++++++- > modules/demux/asf/libasf.h | 42 ++++++++++++ > modules/demux/asf/libasf_guid.h | 2 +- > 6 files changed, 183 insertions(+), 4 deletions(-) > > diff --git a/include/vlc_ancillary.h b/include/vlc_ancillary.h > index 7892d0229c..ca11952e32 100644 > --- a/include/vlc_ancillary.h > +++ b/include/vlc_ancillary.h > @@ -229,5 +229,11 @@ typedef struct vlc_vpx_alpha_t > uint8_t *data; > } vlc_vpx_alpha_t; > > +/** > + * SMPTE timecode data > + */ > + > +#define VLC_ANCILLARY_ID_SMPTE VLC_FOURCC('S','M','P','T') > + > /** @} */ > #endif /* VLC_ANCILLARY_H */ > diff --git a/modules/demux/asf/asfpacket.c b/modules/demux/asf/asfpacket.c > index 2e7790c08e..25f635a353 100644 > --- a/modules/demux/asf/asfpacket.c > +++ b/modules/demux/asf/asfpacket.c > @@ -24,6 +24,7 @@ > #endif > > #include "asfpacket.h" > +#include <vlc_ancillary.h> > #include <limits.h> > > #ifndef NDEBUG > @@ -118,13 +119,23 @@ static int DemuxSubPayload( asf_packet_sys_t *p_packetsys, > if ( b_keyframe ) > p_frag->i_flags |= BLOCK_FLAG_TYPE_I; > > + char psz_timecode[16]; > + snprintf( psz_timecode, sizeof(psz_timecode), "%02u:%02u:%02u:%02u", > + ( p_tkinfo->p_timecode->i_timecode >> 24 ) & 0xFF, > + ( p_tkinfo->p_timecode->i_timecode >> 16 ) & 0xFF, > + ( p_tkinfo->p_timecode->i_timecode >> 8 ) & 0xFF, > + p_tkinfo->p_timecode->i_timecode & 0xFF ); > + struct vlc_ancillary *p_anc = vlc_ancillary_Create( psz_timecode, VLC_ANCILLARY_ID_SMPTE ); > + if ( vlc_frame_AttachAncillary( p_frag, p_anc ) != VLC_SUCCESS ) > + vlc_ancillary_Release( p_anc ); > + > block_ChainAppend( pp_frame, p_frag ); > > return 0; > } > > static void ParsePayloadExtensions( asf_packet_sys_t *p_packetsys, > - const asf_track_info_t *p_tkinfo, > + asf_track_info_t *p_tkinfo, > const uint8_t *p_data, size_t i_data, > bool *b_keyframe ) > { > @@ -185,6 +196,17 @@ static void ParsePayloadExtensions( asf_packet_sys_t *p_packetsys, > if ( i_payload_extensions_size != 48 ) goto sizeerror; > /* const int64_t i_pts = GetQWLE(&p_data[8]); */ > } > + else if ( guidcmp( &p_ext->i_extension_id, &mfasf_sampleextension_smpte_guid ) ) > + { > + if ( i_payload_extensions_size != 14 ) goto sizeerror; > + p_tkinfo->p_timecode->i_reserved = GetDWLE( p_data + 10 ); > + if ( p_tkinfo->p_timecode->i_reserved == 0 ) > + { > + p_tkinfo->p_timecode->i_timecode_range = GetWLE( p_data ); > + p_tkinfo->p_timecode->i_timecode = GetDWLE( p_data + 2 ); > + p_tkinfo->p_timecode->i_user_bits = GetDWLE( p_data + 6 ); > + } > + } > #if 0 > else > { > diff --git a/modules/demux/asf/asfpacket.h b/modules/demux/asf/asfpacket.h > index 6d52a59304..1f74cb2ab3 100644 > --- a/modules/demux/asf/asfpacket.h > +++ b/modules/demux/asf/asfpacket.h > @@ -35,6 +35,7 @@ typedef struct > block_t *p_frame; /* used to gather complete frame */ > asf_object_stream_properties_t *p_sp; > asf_object_extended_stream_properties_t *p_esp; > + asf_payload_extension_system_timecode_t *p_timecode; > int i_cat; > struct > { > diff --git a/modules/demux/asf/libasf.c b/modules/demux/asf/libasf.c > index 8128bcb88c..4188279f5b 100644 > --- a/modules/demux/asf/libasf.c > +++ b/modules/demux/asf/libasf.c > @@ -310,6 +310,107 @@ static void ASF_FreeObject_Index( asf_object_t *p_obj ) > FREENULL( p_index->index_entry ); > } > > +static void ASF_FreeObject_TimecodeIndex( asf_object_t *p_obj ) > +{ > + asf_object_timecode_index_t *p_index = &p_obj->timecode_index; > + > + for ( uint32_t i = 0; i < p_index->i_index_blocks_count; i++ ) > + { > + asf_timecode_index_block_t *p_block = &p_index->p_index_blocks[i]; > + for ( uint32_t k = 0; k < p_block->i_index_entry_count; k++ ) > + FREENULL( p_block->p_index_entries[k].p_offsets ); > + FREENULL( p_block->p_index_entries ); > + FREENULL( p_block->p_block_positions ); > + } > + FREENULL( p_index->p_index_blocks ); > + FREENULL( p_index->p_index_specifiers ); > + p_index->i_index_specifiers_count = 0; > + p_index->i_index_blocks_count = 0; > +} > + > +static int ASF_ReadObject_TimecodeIndex( stream_t *s, asf_object_t *p_obj ) > +{ > + asf_object_timecode_index_t *p_index = &p_obj->timecode_index; > + const uint8_t *p_peek, *p_data; > + > + if ( p_index->i_object_size < 34 > + || p_index->i_object_size > INT32_MAX > + || vlc_stream_Peek(s, &p_peek, p_index->i_object_size) > + < (int64_t)p_index->i_object_size ) > + return VLC_SUCCESS; > + > + p_data = p_peek + ASF_OBJECT_COMMON_SIZE; > + p_index->i_reserved = GetDWLE( p_data ); > + if ( p_index->i_reserved != 1 ) > + return VLC_SUCCESS; > + > + p_index->i_index_specifiers_count = GetWLE( p_data + 4 ); > + p_index->i_index_blocks_count = GetDWLE( p_data + 6 ); > + p_index->p_index_specifiers = NULL; > + p_index->p_index_blocks = NULL; > + p_data += 10; > + > + p_index->p_index_specifiers = calloc( p_index->i_index_specifiers_count, sizeof(asf_timecode_index_specifier_t) ); > + if ( !p_index->p_index_specifiers ) > + { > + p_index->i_index_specifiers_count = 0; > + return VLC_ENOMEM; > + } > + > + for ( uint32_t i = 0; i < p_index->i_index_specifiers_count; i++ ) > + { > + p_index->p_index_specifiers[i].i_stream_number = GetWLE( p_data ); > + p_index->p_index_specifiers[i].i_index_type = GetWLE( p_data + 2 ); > + p_data += 4; > + } > + > + p_index->p_index_blocks = calloc( p_index->i_index_blocks_count, sizeof(asf_timecode_index_block_t) ); > + if (!p_index->p_index_blocks) > + { > + FREENULL( p_index->p_index_specifiers ); > + p_index->i_index_specifiers_count = 0; > + p_index->i_index_blocks_count = 0; > + return VLC_ENOMEM; > + } > + > + for ( uint32_t i = 0; i < p_index->i_index_blocks_count; i++ ) > + { > + asf_timecode_index_block_t *p_block = &p_index->p_index_blocks[i]; > + p_block->i_index_entry_count = GetDWLE( p_data ); > + p_block->i_timecode_range = GetWLE( p_data + 4 ); > + p_data += 6; > + > + p_block->p_block_positions = calloc( p_index->i_index_specifiers_count, sizeof(uint64_t) ); > + if ( !p_block->p_block_positions ) goto no_mem_error; > + for ( uint32_t j = 0; j < p_index->i_index_specifiers_count; j++ ) > + { > + p_block->p_block_positions[j] = GetQWLE( p_data ); > + p_data += 8; > + } > + > + p_block->p_index_entries = calloc( p_block->i_index_entry_count, sizeof(asf_timecode_index_entry_t) ); > + if ( !p_block->p_index_entries ) goto no_mem_error; > + for ( uint32_t j = 0; j < p_block->i_index_entry_count; j++ ) > + { > + p_block->p_index_entries[j].i_timecode = GetDWLE( p_data ); > + p_data += 4; > + p_block->p_index_entries[j].p_offsets = calloc( p_index->i_index_specifiers_count, sizeof(uint32_t) ); > + if ( !p_block->p_index_entries[j].p_offsets ) goto no_mem_error; > + for ( uint32_t k = 0; k < p_index->i_index_specifiers_count; k++ ) > + { > + p_block->p_index_entries[j].p_offsets[k] = GetDWLE( p_data ); > + p_data += 4; > + } > + } > + } > + > + return VLC_SUCCESS; > + > +no_mem_error: > + ASF_FreeObject_TimecodeIndex( p_obj ); > + return VLC_ENOMEM; > +} > + > static int ASF_ReadObject_file_properties( stream_t *s, asf_object_t *p_obj ) > { > asf_object_file_properties_t *p_fp = &p_obj->file_properties; > @@ -1447,6 +1548,8 @@ static const struct ASF_Object_Function_entry > ASF_ReadObject_Data, ASF_FreeObject_Null }, > { &asf_object_simple_index_guid, ASF_OBJECT_INDEX, > ASF_ReadObject_Index, ASF_FreeObject_Index }, > + { &asf_object_timecode_index_guid, ASF_OBJECT_INDEX, > + ASF_ReadObject_TimecodeIndex, ASF_FreeObject_TimecodeIndex }, > { &asf_object_file_properties_guid, ASF_OBJECT_FILE_PROPERTIES, > ASF_ReadObject_file_properties, ASF_FreeObject_Null }, > { &asf_object_stream_properties_guid, ASF_OBJECT_STREAM_PROPERTIES, > @@ -1615,6 +1718,7 @@ static const struct > { &asf_object_data_guid, "Data" }, > { &asf_object_index_guid, "Index" }, > { &asf_object_simple_index_guid, "Simple Index" }, > + { &asf_object_timecode_index_guid, "Timecode Index"}, > { &asf_object_file_properties_guid, "File Properties" }, > { &asf_object_stream_properties_guid, "Stream Properties" }, > { &asf_object_content_description_guid, "Content Description" }, > @@ -1715,6 +1819,7 @@ asf_object_root_t *ASF_ReadObjectRoot( stream_t *s, int b_seekable ) > p_root->p_data = NULL; > p_root->p_fp = NULL; > p_root->p_index = NULL; > + p_root->p_timecode_index = NULL; > p_root->p_metadata = NULL; > > for( ; ; ) > @@ -1737,8 +1842,11 @@ asf_object_root_t *ASF_ReadObjectRoot( stream_t *s, int b_seekable ) > p_root->p_data = (asf_object_data_t*)p_obj; > break; > case( ASF_OBJECT_INDEX ): > - if ( p_root->p_index ) break; > - p_root->p_index = (asf_object_index_t*)p_obj; > + if ( p_root->p_index && p_root->p_timecode_index) break; > + if ( guidcmp(&p_obj->common.i_object_id, &asf_object_timecode_index_guid) ) > + p_root->p_timecode_index = (asf_object_timecode_index_t *)p_obj; > + else > + p_root->p_index = (asf_object_index_t *)p_obj; > break; > default: > msg_Warn( s, "unknown top-level object found: " GUID_FMT, > diff --git a/modules/demux/asf/libasf.h b/modules/demux/asf/libasf.h > index 106c825a77..8981556b36 100644 > --- a/modules/demux/asf/libasf.h > +++ b/modules/demux/asf/libasf.h > @@ -54,6 +54,26 @@ typedef struct > > } asf_index_entry_t; > > +typedef struct > +{ > + uint16_t i_stream_number; > + uint16_t i_index_type; > +} asf_timecode_index_specifier_t; > + > +typedef struct > +{ > + uint32_t i_timecode; > + uint32_t *p_offsets; > +} asf_timecode_index_entry_t; > + > +typedef struct > +{ > + uint32_t i_index_entry_count; > + uint16_t i_timecode_range; > + uint64_t *p_block_positions; > + asf_timecode_index_entry_t *p_index_entries; > +} asf_timecode_index_block_t; > + > /**************************************************************************** > * High level asf object > ****************************************************************************/ > @@ -90,6 +110,18 @@ typedef struct > > } asf_object_index_t; > > +typedef struct > +{ > + ASF_OBJECT_COMMON > + uint32_t i_reserved; /* must be 1 */ > + uint16_t i_index_specifiers_count; > + uint32_t i_index_blocks_count; > + > + asf_timecode_index_specifier_t *p_index_specifiers; > + asf_timecode_index_block_t *p_index_blocks; > + > +} asf_object_timecode_index_t; > + > /**************************************************************************** > * Sub level asf object > ****************************************************************************/ > @@ -260,6 +292,14 @@ typedef struct > uint32_t i_info_length; > char *pi_info; > } asf_payload_extension_system_t; > + > +typedef struct > +{ > + uint16_t i_timecode_range; > + uint32_t i_timecode; > + uint32_t i_user_bits; > + uint32_t i_reserved; /* must be 0 */ > +} asf_payload_extension_system_timecode_t; > #define ASF_EXTENSION_VIDEOFRAME_NEWFRAME 0x08 > #define ASF_EXTENSION_VIDEOFRAME_IFRAME 0x01 > #define ASF_EXTENSION_VIDEOFRAME_TYPE_MASK 0x07 > @@ -350,6 +390,7 @@ typedef struct > asf_object_data_t *p_data; > /* could be NULL if !b_seekable or not-present */ > asf_object_index_t *p_index; > + asf_object_timecode_index_t *p_timecode_index; > > /* from asf_object_header_t */ > asf_object_file_properties_t *p_fp; > @@ -368,6 +409,7 @@ typedef union asf_object_u > asf_object_header_t header; > asf_object_data_t data; > asf_object_index_t index; > + asf_object_timecode_index_t timecode_index; > asf_object_root_t root; > asf_object_file_properties_t file_properties; > asf_object_stream_properties_t stream_properties; > diff --git a/modules/demux/asf/libasf_guid.h b/modules/demux/asf/libasf_guid.h > index 984d50b0f7..3a59546829 100644 > --- a/modules/demux/asf/libasf_guid.h > +++ b/modules/demux/asf/libasf_guid.h > @@ -232,7 +232,7 @@ static const vlc_guid_t mfasf_sampleextension_sampleduration_guid = > static const vlc_guid_t mfasf_sampleextension_outputcleanpoint_guid = > {0xF72A3C6F, 0x6EB4, 0x4EBC, {0xB1, 0x92, 0x09, 0xAD, 0x97, 0x59, 0xE8, 0x28}}; > > -static const vlc_guid_t mfasf_sampleextension_smtpe_guid = > +static const vlc_guid_t mfasf_sampleextension_smpte_guid = > {0x399595EC, 0x8667, 0x4E2D, {0x8F, 0xDB, 0x98, 0x81, 0x4C, 0xE7, 0x6C, 0x1E}}; > > static const vlc_guid_t mfasf_sampleextension_filename_guid = > -- > 2.43.0 > > _______________________________________________ > vlc-devel mailing list > To unsubscribe or modify your subscription options: > https://mailman.videolan.org/listinfo/vlc-devel _______________________________________________ vlc-devel mailing list To unsubscribe or modify your subscription options: https://mailman.videolan.org/listinfo/vlc-devel