@@ -48,6 +48,7 @@ struct spdifContext {
4848 uint8_t out_buffer [OUTBUF_SIZE ];
4949 bool need_close ;
5050 bool use_dts_hd ;
51+ int dropped_startup_packets ;
5152 struct mp_aframe * fmt ;
5253 int sstride ;
5354 struct mp_aframe_pool * pool ;
@@ -74,24 +75,47 @@ static int write_packet(void *p, const uint8_t *buf, int buf_size)
7475 return buf_size ;
7576}
7677
77- // (called on both filter destruction _and_ if lavf fails to init)
78- static void ad_spdif_destroy (struct mp_filter * da )
78+ static void close_lavf_context (struct spdifContext * spdif_ctx , bool write_trailer )
7979{
80- struct spdifContext * spdif_ctx = da -> priv ;
81- AVFormatContext * lavf_ctx = spdif_ctx -> lavf_ctx ;
80+ AVFormatContext * lavf_ctx = spdif_ctx -> lavf_ctx ;
8281
8382 if (lavf_ctx ) {
84- if (spdif_ctx -> need_close )
83+ if (write_trailer && spdif_ctx -> need_close )
8584 av_write_trailer (lavf_ctx );
8685 if (lavf_ctx -> pb )
8786 av_freep (& lavf_ctx -> pb -> buffer );
8887 avio_context_free (& lavf_ctx -> pb );
8988 avformat_free_context (lavf_ctx );
9089 spdif_ctx -> lavf_ctx = NULL ;
9190 }
91+ spdif_ctx -> need_close = false;
92+ }
93+
94+ // (called on both filter destruction _and_ if lavf fails to init)
95+ static void ad_spdif_destroy (struct mp_filter * da )
96+ {
97+ struct spdifContext * spdif_ctx = da -> priv ;
98+
99+ close_lavf_context (spdif_ctx , true);
92100 mp_free_av_packet (& spdif_ctx -> avpkt );
93101}
94102
103+ static void ad_spdif_reset (struct mp_filter * da )
104+ {
105+ struct spdifContext * spdif_ctx = da -> priv ;
106+
107+ close_lavf_context (spdif_ctx , false);
108+ TA_FREEP (& spdif_ctx -> fmt );
109+ }
110+
111+ // TrueHD/MLP major sync starts with f8 72 6f ba/bb after the AU header.
112+ static bool truehd_has_major_sync (AVPacket * pkt )
113+ {
114+ return pkt -> size >= 8 && pkt -> data [4 ] == 0xf8 &&
115+ pkt -> data [5 ] == 0x72 && pkt -> data [6 ] == 0x6f &&
116+ (pkt -> data [7 ] & 0xfe ) == 0xba ;
117+ }
118+
95119static void determine_codec_params (struct mp_filter * da , AVPacket * pkt ,
96120 int * out_profile , int * out_rate )
97121{
@@ -160,9 +184,22 @@ static void determine_codec_params(struct mp_filter *da, AVPacket *pkt,
160184done :
161185 av_frame_free (& frame );
162186 avcodec_free_context (& ctx );
187+ }
163188
164- if (profile == AV_PROFILE_UNKNOWN )
165- MP_WARN (da , "Failed to parse codec profile.\n" );
189+ // Some codecs do not need every probed value for spdif muxer setup.
190+ static bool codec_params_warning_needed (struct spdifContext * spdif_ctx ,
191+ int profile , int rate )
192+ {
193+ switch (spdif_ctx -> codec_id ) {
194+ case AV_CODEC_ID_DTS :
195+ return spdif_ctx -> use_dts_hd && profile == AV_PROFILE_UNKNOWN ;
196+ case AV_CODEC_ID_TRUEHD :
197+ return profile == AV_PROFILE_UNKNOWN || rate <= 0 ;
198+ case AV_CODEC_ID_AC3 :
199+ return rate <= 0 ;
200+ default :
201+ return false;
202+ }
166203}
167204
168205static int init_filter (struct mp_filter * da )
@@ -175,6 +212,8 @@ static int init_filter(struct mp_filter *da)
175212 int c_rate = 0 ;
176213 determine_codec_params (da , pkt , & profile , & c_rate );
177214 MP_VERBOSE (da , "In: profile=%d samplerate=%d\n" , profile , c_rate );
215+ if (codec_params_warning_needed (spdif_ctx , profile , c_rate ))
216+ MP_WARN (da , "Failed to parse codec parameters.\n" );
178217
179218 AVFormatContext * lavf_ctx = avformat_alloc_context ();
180219 if (!lavf_ctx )
@@ -318,6 +357,7 @@ static void ad_spdif_process(struct mp_filter *da)
318357 struct demux_packet * mpkt = inframe .data ;
319358 struct mp_aframe * out = NULL ;
320359 double pts = mpkt -> pts ;
360+ bool drop_packet = false;
321361
322362 if (!spdif_ctx -> avpkt ) {
323363 spdif_ctx -> avpkt = av_packet_alloc ();
@@ -326,6 +366,16 @@ static void ad_spdif_process(struct mp_filter *da)
326366 mp_set_av_packet (spdif_ctx -> avpkt , mpkt , NULL );
327367 spdif_ctx -> avpkt -> pts = spdif_ctx -> avpkt -> dts = 0 ;
328368 if (!spdif_ctx -> lavf_ctx ) {
369+ // A fresh TrueHD spdif muxer needs a major sync before it can begin
370+ // muxing the stream, and init_filter() probes codec parameters from
371+ // this packet as well, so wait for major sync before intitializing.
372+ if (spdif_ctx -> codec_id == AV_CODEC_ID_TRUEHD &&
373+ !truehd_has_major_sync (spdif_ctx -> avpkt ))
374+ {
375+ spdif_ctx -> dropped_startup_packets ++ ;
376+ drop_packet = true;
377+ goto done ;
378+ }
329379 if (init_filter (da ) < 0 )
330380 goto done ;
331381 mp_assert (spdif_ctx -> avpkt );
@@ -339,6 +389,12 @@ static void ad_spdif_process(struct mp_filter *da)
339389 MP_ERR (da , "spdif mux error: '%s'\n" , mp_strerror (AVUNERROR (ret )));
340390 goto done ;
341391 }
392+ if (spdif_ctx -> dropped_startup_packets ) {
393+ MP_VERBOSE (da , "dropped %d TrueHD packet%s before major sync\n" ,
394+ spdif_ctx -> dropped_startup_packets ,
395+ spdif_ctx -> dropped_startup_packets == 1 ? "" : "s" );
396+ spdif_ctx -> dropped_startup_packets = 0 ;
397+ }
342398
343399 out = mp_aframe_new_ref (spdif_ctx -> fmt );
344400 int samples = spdif_ctx -> out_buffer_len / spdif_ctx -> sstride ;
@@ -360,6 +416,8 @@ static void ad_spdif_process(struct mp_filter *da)
360416 talloc_free (mpkt );
361417 if (out ) {
362418 mp_pin_in_write (da -> ppins [1 ], MAKE_FRAME (MP_FRAME_AUDIO , out ));
419+ } else if (drop_packet ) {
420+ mp_filter_internal_mark_progress (da );
363421 } else {
364422 mp_filter_internal_mark_failed (da );
365423 }
@@ -423,6 +481,7 @@ static const struct mp_filter_info ad_spdif_filter = {
423481 .name = "ad_spdif" ,
424482 .priv_size = sizeof (struct spdifContext ),
425483 .process = ad_spdif_process ,
484+ .reset = ad_spdif_reset ,
426485 .destroy = ad_spdif_destroy ,
427486};
428487
0 commit comments