2222
2323#include <libavformat/avformat.h>
2424#include <libavcodec/avcodec.h>
25+ #include <libavutil/intreadwrite.h>
2526#include <libavutil/opt.h>
2627
2728#include "audio/aframe.h"
3738#include "options/options.h"
3839
3940#define OUTBUF_SIZE 65536
41+ #define TRUEHD_MAJOR_SYNC_WARN_INTERVAL 6000
4042
4143struct spdifContext {
4244 struct mp_log * log ;
@@ -48,6 +50,10 @@ struct spdifContext {
4850 uint8_t out_buffer [OUTBUF_SIZE ];
4951 bool need_close ;
5052 bool use_dts_hd ;
53+ bool codec_params_probed ;
54+ int codec_profile ;
55+ int codec_rate ;
56+ unsigned int dropped_startup_packets ;
5157 struct mp_aframe * fmt ;
5258 int sstride ;
5359 struct mp_aframe_pool * pool ;
@@ -74,24 +80,45 @@ static int write_packet(void *p, const uint8_t *buf, int buf_size)
7480 return buf_size ;
7581}
7682
77- // (called on both filter destruction _and_ if lavf fails to init)
78- static void ad_spdif_destroy (struct mp_filter * da )
83+ static void close_lavf_context (struct spdifContext * spdif_ctx , bool write_trailer )
7984{
80- struct spdifContext * spdif_ctx = da -> priv ;
81- AVFormatContext * lavf_ctx = spdif_ctx -> lavf_ctx ;
85+ AVFormatContext * lavf_ctx = spdif_ctx -> lavf_ctx ;
8286
8387 if (lavf_ctx ) {
84- if (spdif_ctx -> need_close )
88+ if (write_trailer && spdif_ctx -> need_close )
8589 av_write_trailer (lavf_ctx );
8690 if (lavf_ctx -> pb )
8791 av_freep (& lavf_ctx -> pb -> buffer );
8892 avio_context_free (& lavf_ctx -> pb );
8993 avformat_free_context (lavf_ctx );
9094 spdif_ctx -> lavf_ctx = NULL ;
9195 }
96+ spdif_ctx -> need_close = false;
97+ TA_FREEP (& spdif_ctx -> fmt );
98+ }
99+
100+ // (called on both filter destruction _and_ if lavf fails to init)
101+ static void ad_spdif_destroy (struct mp_filter * da )
102+ {
103+ struct spdifContext * spdif_ctx = da -> priv ;
104+
105+ close_lavf_context (spdif_ctx , true);
92106 mp_free_av_packet (& spdif_ctx -> avpkt );
93107}
94108
109+ static void ad_spdif_reset (struct mp_filter * da )
110+ {
111+ struct spdifContext * spdif_ctx = da -> priv ;
112+
113+ close_lavf_context (spdif_ctx , false);
114+ spdif_ctx -> dropped_startup_packets = 0 ;
115+ }
116+
117+ static bool truehd_has_major_sync (const AVPacket * pkt )
118+ {
119+ return pkt -> size >= 8 && AV_RB32 (pkt -> data + 4 ) == 0xf8726fba ;
120+ }
121+
95122static void determine_codec_params (struct mp_filter * da , AVPacket * pkt ,
96123 int * out_profile , int * out_rate )
97124{
@@ -171,10 +198,17 @@ static int init_filter(struct mp_filter *da)
171198
172199 AVPacket * pkt = spdif_ctx -> avpkt ;
173200
174- int profile = AV_PROFILE_UNKNOWN ;
175- int c_rate = 0 ;
176- determine_codec_params (da , pkt , & profile , & c_rate );
177- MP_VERBOSE (da , "In: profile=%d samplerate=%d\n" , profile , c_rate );
201+ if (!spdif_ctx -> codec_params_probed ) {
202+ spdif_ctx -> codec_profile = AV_PROFILE_UNKNOWN ;
203+ determine_codec_params (da , pkt , & spdif_ctx -> codec_profile ,
204+ & spdif_ctx -> codec_rate );
205+ spdif_ctx -> codec_params_probed = true;
206+ MP_VERBOSE (da , "In: profile=%d samplerate=%d\n" ,
207+ spdif_ctx -> codec_profile , spdif_ctx -> codec_rate );
208+ }
209+
210+ int profile = spdif_ctx -> codec_profile ;
211+ int c_rate = spdif_ctx -> codec_rate ;
178212
179213 AVFormatContext * lavf_ctx = avformat_alloc_context ();
180214 if (!lavf_ctx )
@@ -318,6 +352,7 @@ static void ad_spdif_process(struct mp_filter *da)
318352 struct demux_packet * mpkt = inframe .data ;
319353 struct mp_aframe * out = NULL ;
320354 double pts = mpkt -> pts ;
355+ bool drop_packet = false;
321356
322357 if (!spdif_ctx -> avpkt ) {
323358 spdif_ctx -> avpkt = av_packet_alloc ();
@@ -326,6 +361,22 @@ static void ad_spdif_process(struct mp_filter *da)
326361 mp_set_av_packet (spdif_ctx -> avpkt , mpkt , NULL );
327362 spdif_ctx -> avpkt -> pts = spdif_ctx -> avpkt -> dts = 0 ;
328363 if (!spdif_ctx -> lavf_ctx ) {
364+ // A fresh TrueHD spdif muxer needs a major sync to initialize its
365+ // stream parameters, so wait for major sync before initializing.
366+ if (spdif_ctx -> codec_id == AV_CODEC_ID_TRUEHD &&
367+ !truehd_has_major_sync (spdif_ctx -> avpkt ))
368+ {
369+ spdif_ctx -> dropped_startup_packets ++ ;
370+ if (spdif_ctx -> dropped_startup_packets %
371+ TRUEHD_MAJOR_SYNC_WARN_INTERVAL == 0 )
372+ {
373+ MP_WARN (da , "Still waiting for TrueHD major sync after "
374+ "dropping %u packets.\n" ,
375+ spdif_ctx -> dropped_startup_packets );
376+ }
377+ drop_packet = true;
378+ goto done ;
379+ }
329380 if (init_filter (da ) < 0 )
330381 goto done ;
331382 mp_assert (spdif_ctx -> avpkt );
@@ -339,6 +390,12 @@ static void ad_spdif_process(struct mp_filter *da)
339390 MP_ERR (da , "spdif mux error: '%s'\n" , mp_strerror (AVUNERROR (ret )));
340391 goto done ;
341392 }
393+ if (spdif_ctx -> dropped_startup_packets ) {
394+ MP_VERBOSE (da , "dropped %u TrueHD packet%s before major sync\n" ,
395+ spdif_ctx -> dropped_startup_packets ,
396+ spdif_ctx -> dropped_startup_packets == 1 ? "" : "s" );
397+ spdif_ctx -> dropped_startup_packets = 0 ;
398+ }
342399
343400 out = mp_aframe_new_ref (spdif_ctx -> fmt );
344401 int samples = spdif_ctx -> out_buffer_len / spdif_ctx -> sstride ;
@@ -360,6 +417,8 @@ static void ad_spdif_process(struct mp_filter *da)
360417 talloc_free (mpkt );
361418 if (out ) {
362419 mp_pin_in_write (da -> ppins [1 ], MAKE_FRAME (MP_FRAME_AUDIO , out ));
420+ } else if (drop_packet ) {
421+ mp_filter_internal_mark_progress (da );
363422 } else {
364423 mp_filter_internal_mark_failed (da );
365424 }
@@ -423,6 +482,7 @@ static const struct mp_filter_info ad_spdif_filter = {
423482 .name = "ad_spdif" ,
424483 .priv_size = sizeof (struct spdifContext ),
425484 .process = ad_spdif_process ,
485+ .reset = ad_spdif_reset ,
426486 .destroy = ad_spdif_destroy ,
427487};
428488
0 commit comments