Aves_mio0.88/catt_info.md
2026-10-03 12:51:15 +02:00

31 KiB
Raw Blame History

Sì, l’idea è possibile, ma bisogna distinguere due modi molto diversi di far apparire più pezzi come un unico video.

  1. Non basta dividere l’MP4 in file più piccoli

Non possiamo prendere l’MP4 completo e spezzarlo così:

video_part_01.mp4 video_part_02.mp4 video_part_03.mp4

per poi concatenarli lato server come se fossero un unico file.

Il receiver avrebbe comunque bisogno di:

una dimensione totale stabile; offset Range coerenti; un’unica timeline; timestamp continui; intestazioni e indici validi; transizioni senza reset del decoder.

Inoltre, il problema attuale non è la dimensione di segment_00000.m4s: il receiver lo interrompe sempre dopo 589.824 byte, anche se il segmento completo è circa 2,34 MB. Questo indica che trova dati che non riesce a interpretare, non che il segmento sia semplicemente troppo grande.

Ridurre i segmenti fMP4 da circa 3 secondi a 1 secondo probabilmente non risolverebbe, perché il formato interno rimarrebbe:

moof + mdat

che è proprio quello che il receiver attuale sta rifiutando.

  1. La soluzione compatibile è HLS con segmenti MPEG-TS

La tua idea funziona bene se ogni pacchetto è un segmento autonomo MPEG Transport Stream:

master.m3u8 segment_00000.ts segment_00001.ts segment_00002.ts

La playlist li presenta come un unico video continuo:

#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXTINF:3.000, segment_00000.ts #EXTINF:3.000, segment_00001.ts #EXTINF:3.000, segment_00002.ts

Il receiver vede una sola timeline, anche se il server consegna tanti file. Google Cast documenta il supporto del contenitore MP2T, oltre a HLS come protocollo di streaming.

Questa strada è probabilmente più compatibile con il vecchio runtime del tuo TV:

CrKey/1.56 Chrome 92 Android 9

Perché MPEG-TS è diverso da fMP4

Nel nostro HLS fMP4 abbiamo:

init.mp4 segment_00000.m4s segment_00001.m4s

Ogni .m4s dipende da init.mp4 e dal supporto Media Source Extensions del player.

Con MPEG-TS avremmo invece:

segment_00000.ts segment_00001.ts

Ogni segmento contiene le informazioni necessarie per trasportare audio e video. Il player può elaborare i segmenti in successione senza EXT-X-MAP e senza initialization segment fMP4.

Possiamo conservare la transcodifica hardware

Sì. La parte costosa che già funziona può rimanere:

MediaCodec decoder → ridimensionamento 1080p → MediaCodec H.264 High Level 4.1 → AAC

Dobbiamo sostituire solamente il muxer finale:

oggi: H.264 + AAC → fragmented MP4

nuovo: H.264 + AAC → MPEG-TS

Il problema è che Media3 Transformer offre il muxer MP4 e fragmented MP4 che abbiamo usato, ma non ci sta fornendo direttamente un’esportazione HLS MPEG-TS. Media3 permette comunque di sostituire componenti della pipeline quando serve più controllo.

Architettura possibile

La pipeline dovrebbe diventare:

Media3 / MediaCodec ↓ campioni codificati H.264 e AAC ↓ MPEG-TS muxer ↓ segment_00000.ts.part ↓ segmento completo segment_00000.ts ↓ aggiornamento master.m3u8

Dopo tre segmenti:

start.jpg → circa 4-6 secondi di preparazione → queue HLS → segmenti TS letti dal Default Receiver → muxing continua in background

Il comportamento sarebbe trasparente come desideri.

Dimensione consigliata dei pacchetti

Userei inizialmente:

durata segmento: circa 3 secondi buffer iniziale: 3 segmenti contenuto pronto prima del play: circa 9 secondi

Non bisogna creare segmenti estremamente piccoli. Google specifica che il Web Receiver non supporta segmenti sotto 0,1 secondi, ma segmenti da 2-4 secondi sono una scelta molto più normale e gestibile.

Dato che il telefono produce circa tre secondi di video in un secondo di elaborazione, preparare tre segmenti dovrebbe richiedere all’incirca:

4-6 secondi

come nel test fMP4.

“Uno unico” anche senza HLS?

Esiste anche una variante server-side:

GET /video.ts → il server scrive una sequenza continua di pacchetti MPEG-TS → Transfer-Encoding: chunked

Il TV vedrebbe un singolo URL invece di una playlist.

Non la consiglierei per il primo test, perché:

il seek è più difficile; non conosciamo la lunghezza finale; il client può chiudere e riaprire la connessione; il recupero dopo errori è meno robusto; HLS gestisce già timeline, retry e disponibilità progressiva.

Quindi la soluzione più pulita resta:

molti segmenti .ts → una sola playlist .m3u8 → un solo video logico sul TV

Raccomandazione

Sì, conviene provare HLS MPEG-TS prima di rinunciare all’avvio rapido o adottare un Custom Receiver.

Non conviene invece:

ridurre semplicemente i .m4s; concatenare file MP4 indipendenti; servire un MP4 incompleto in crescita; simulare un file unico con Content-Length variabile. Ordine di sviluppo consigliato Conservare il codice HLS fMP4 come prototipo funzionante. Aggiungere un muxer MPEG-TS nativo. Riutilizzare H.264 Level 4.1 e AAC già prodotti. Pubblicare segmenti .ts atomicamente. Generare playlist HLS senza EXT-X-MAP. Servire i segmenti con: Content-Type: video/mp2t

Testare con VLC. Testare con CC1AD845. Se il Default Receiver legge segment_00000.ts, segment_00001.ts e segment_00002.ts, collegare il flusso alla transcodifica simultanea. Aggiungere Foreground Service, WakeLock e WiFiLock per lo schermo spento.

In breve: sì, possiamo fare pacchetti piccoli che il TV vede come un unico video, ma devono essere segmenti HLS MPEG-TS correttamente muxati, non pezzi arbitrari di MP4.

Sì, è più difficile del percorso fMP4 che abbiamo appena realizzato, ma non è fuori portata. Direi difficoltà medio-alta, soprattutto perché Media3 Transformer non offre direttamente un output HLS MPEG-TS pronto: dovremo intercettare i campioni H.264/AAC già codificati e inserirli correttamente nei pacchetti MPEG-TS. Media3 permette comunque di sostituire componenti della pipeline quando serve maggiore controllo.

La parte già risolta

Possiamo riutilizzare quasi tutto ciò che abbiamo costruito:

risoluzione del file originale; transcodifica hardware con MediaCodec; H.264 High Profile Level 4.1; AAC; riduzione a 1080p; bitrate video; cache per mediaId; playlist dinamica; pubblicazione atomica; endpoint HTTP HLS; segnale READY; schermata start.jpg; integrazione della queue Cast.

Google Cast supporta sia HLS sia il contenitore MPEG-2 Transport Stream, identificato normalmente come video/mp2t.

Quindi non ripartiamo da zero. Cambia principalmente questo componente:

attuale: H.264 + AAC → Fragmented MP4 → moof + mdat → segmenti .m4s

nuovo: H.264 + AAC → MPEG-TS muxer → pacchetti TS → segmenti .ts

La parte complessa

Un muxer MPEG-TS deve costruire correttamente:

pacchetti da 188 byte; PAT, Program Association Table; PMT, Program Map Table; PID separati per audio e video; PES per H.264 e AAC; PTS e DTS; continuity counter; access unit H.264 in formato Annex B; intestazioni ADTS per AAC, se richieste; segmentazione solo in corrispondenza di un keyframe; timestamp continui fra un segmento e il successivo.

Non basta quindi sostituire l’estensione:

.m4s → .ts

I dati interni devono essere rimuxati realmente.

Quanto lavoro richiede

Una prima implementazione diagnostica richiede indicativamente questi passaggi:

Creare un Muxer.Factory personalizzato per Media3. Ricevere le tracce H.264 e AAC da Transformer. Convertire i campioni H.264 nel formato atteso dal Transport Stream. Generare PAT e PMT. Incapsulare video e audio in PES. Suddividere i PES in pacchetti TS da 188 byte. Chiudere un segmento .ts ogni circa 3 secondi, sul primo keyframe utile. Aggiornare atomicamente la playlist. Validare il flusso con FFmpeg e VLC. Provarlo sul Default Media Receiver.

La difficoltà maggiore è la correttezza di timestamp, keyframe e pacchettizzazione MPEG-TS. La parte Dart, server e queue è invece già quasi pronta.

Strategia più sicura

Non sostituirei subito il percorso fMP4. Creerei una pipeline parallela:

cast_ts_cache.dart cast_ts_optimizer.dart CastTsSegmentingMuxer.kt

Con un nuovo output:

cache/aves_cast_ts/1000119720/ ├── master.m3u8 ├── segment_00000.ts ├── segment_00001.ts ├── segment_00002.ts ├── session.json └── complete.flag

La playlist sarebbe più semplice:

#EXTM3U #EXT-X-VERSION:3 #EXT-X-TARGETDURATION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-PLAYLIST-TYPE:EVENT #EXTINF:3.000, segment_00000.ts #EXTINF:3.000, segment_00001.ts

Non servirebbe:

#EXT-X-MAP init.mp4

Il server esporrebbe i segmenti con:

Content-Type: video/mp2t

Prima versione consigliata

Per ridurre la complessità, partirei con una versione molto vincolata:

Video: H.264 Audio: AAC-LC Risoluzione massima: 1920x1080 Frame rate: 30 fps Keyframe: ogni secondo Segmento: circa 3 secondi Una sola qualità Nessun sottotitolo Nessun HDR Nessun seek durante la transcodifica iniziale

Questo evita di costruire subito un muxer MPEG-TS universale.

Tempo di avvio previsto

Con le prestazioni già misurate:

3 secondi di video prodotti in circa 1 secondo

potremmo pubblicare tre segmenti da circa 3 secondi in approssimativamente:

4-6 secondi

Quindi il comportamento finale resterebbe:

start.jpg → pochi secondi → video HLS MPEG-TS → transcodifica continua in background

Rischio tecnico

Il rischio principale non è riuscire a produrre MPEG-TS. Il rischio è scoprire un’altra peculiarità del vecchio runtime Cast dopo aver completato il muxer.

Per limitarlo, la prima milestone dovrebbe essere molto piccola:

generare soltanto 10-15 secondi → 4 o 5 segmenti .ts → playlist VOD statica → provare immediatamente con CC1AD845

Se il Default Receiver legge:

segment_00000.ts segment_00001.ts segment_00002.ts

e passa a PLAYING, allora investiamo nel muxer incrementale completo.

Se fallisce già sul primo .ts, fermiamo lo sviluppo prima di costruire tutta la pipeline.

Valutazione finale Difficoltà: medio-alta. Fattibilità: sì. Codice riutilizzabile: molto, soprattutto Dart, cache, server e queue. Parte nuova critica: muxer MPEG-TS nativo. Approccio prudente: produrre prima un breve HLS-TS statico di prova. Beneficio potenziale: avvio rapido senza Custom Receiver.

La decisione più razionale è quindi procedere con un prototipo MPEG-TS breve e statico, non con il muxer completo. Se quel prototipo viene riprodotto da CC1AD845, completiamo poi la generazione on the fly.

Sì, ed è la scelta migliore prima di modificare ancora Flutter. Possiamo creare sul Mac un piccolo HLS MPEG-TS di 15 secondi, servirlo con CORS e inviarlo direttamente al Default Media Receiver tramite catt.

Google Cast supporta HLS e il contenitore MPEG-TS/MP2T.

  1. Verifica FFmpeg ffmpeg -version

Se non è installato:

brew install ffmpeg

  1. Usa il filmato originale oppure l’MP4 convertito

Se hai ancora sul Mac:

cast_1000119720.mp4

usa quello, perché ha già H.264 Level 4.1 e AAC compatibili.

Verifica:

ls -lh cast_1000119720.mp4

  1. Crea un HLS MPEG-TS breve rm -rf hls_ts_test mkdir hls_ts_test

Genera 15 secondi con segmenti di 3 secondi:

ffmpeg
-y
-i cast_1000119720.mp4
-t 15
-c:v libx264
-profile:v high
-level:v 4.1
-preset veryfast
-b:v 5000k
-maxrate 6000k
-bufsize 12000k
-r 30
-g 90
-keyint_min 90
-sc_threshold 0
-c:a aac
-b:a 160k
-ac 2
-ar 48000
-f hls
-hls_time 3
-hls_list_size 0
-hls_playlist_type vod
-hls_segment_type mpegts
-hls_flags independent_segments
-hls_segment_filename 'hls_ts_test/segment_%05d.ts'
hls_ts_test/master.m3u8

FFmpeg può generare una playlist HLS con segmenti .ts; i tagli avvengono sui keyframe, quindi abbiamo allineato il GOP a tre secondi a 30 fps.

  1. Controlla l’output ls -lh hls_ts_test

Dovresti trovare:

master.m3u8 segment_00000.ts segment_00001.ts segment_00002.ts segment_00003.ts segment_00004.ts

Controlla la playlist:

cat hls_ts_test/master.m3u8

Deve contenere riferimenti ai file .ts, senza:

EXT-X-MAP init.mp4

  1. Verifica localmente ffplay hls_ts_test/master.m3u8

Oppure:

open -a VLC hls_ts_test/master.m3u8

  1. Crea un piccolo server HTTP con CORS

Il Default Receiver richiede che le risorse siano raggiungibili dal televisore e che il server risponda con CORS. Google indica CORS come requisito importante per la riproduzione dei media Cast.

Crea questo server nella cartella corrente:

cat > hls_cors_server.py <<'PY' from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer import os

ROOT = os.path.abspath("hls_ts_test") PORT = 8000

class Handler(SimpleHTTPRequestHandler): extensions_map = { **SimpleHTTPRequestHandler.extensions_map, ".m3u8": "application/vnd.apple.mpegurl", ".ts": "video/mp2t", }

def end_headers(self):
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header(
        "Access-Control-Expose-Headers",
        "Content-Length, Content-Type, Accept-Ranges",
    )
    self.send_header("Cache-Control", "no-cache")
    super().end_headers()

def do_OPTIONS(self):
    self.send_response(204)
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header("Access-Control-Allow-Methods", "GET, HEAD, OPTIONS")
    self.send_header("Access-Control-Allow-Headers", "Range")
    self.end_headers()

if name == "main": os.chdir(ROOT) server = ThreadingHTTPServer(("0.0.0.0", PORT), Handler) print(f"Serving {ROOT} on port {PORT}") server.serve_forever() PY

Avvialo:

python3 hls_cors_server.py

Lascialo attivo.

  1. Trova l’IP del Mac

In un altro terminale:

ipconfig getifaddr en0

Se non restituisce nulla:

ipconfig getifaddr en1

Supponiamo che restituisca:

192.168.1.50

L’URL sarà:

http://192.168.1.50:8000/master.m3u8

Verificalo:

curl -I
'http://192.168.1.50:8000/master.m3u8'

Deve mostrare:

Content-Type: application/vnd.apple.mpegurl Access-Control-Allow-Origin: *

Verifica un segmento:

curl -I
'http://192.168.1.50:8000/segment_00000.ts'

Deve mostrare:

Content-Type: video/mp2t

  1. Installa catt

La versione corrente di catt richiede Python 3.11 o superiore e può inviare URL direttamente a un dispositivo Cast.

Metodo consigliato:

brew install pipx pipx ensurepath pipx install catt

Chiudi e riapri il terminale, oppure esegui:

source ~/.zshrc

Verifica:

catt --version

  1. Trova il dispositivo Cast catt scan

Annota il nome esatto mostrato, per esempio:

TV Salotto

  1. Invia direttamente l’HLS MPEG-TS catt -d 'TV Salotto' cast
    'http://192.168.1.50:8000/master.m3u8'

Se hai un solo dispositivo Cast, puoi provare anche:

catt cast
'http://192.168.1.50:8000/master.m3u8'

Interpretazione Se il video viene riprodotto

Abbiamo una conferma importante:

Default Media Receiver → HLS MPEG-TS compatibile

A quel punto vale la pena implementare il muxer MPEG-TS in Android e riutilizzare tutta la pipeline incrementale già costruita.

Se fallisce

Prima controlla il terminale del server:

il TV ha richiesto master.m3u8? ha richiesto segment_00000.ts? ha proseguito con segment_00001.ts?

Se chiede più segmenti ma non riproduce, il problema può essere nella codifica o nei timestamp. Se non richiede nessun segmento, può essere un problema di URL, firewall o CORS.

Se catt non gestisce correttamente l’HLS

Puoi usare una pagina Web che invia stream HLS direttamente a Chromecast, ma catt è preferibile perché consente di mantenere il test da riga di comando. catt supporta URL e media locali tramite il Default Cast controller.

Vantaggio del test

Questa prova è completamente separata da:

Flutter; Media3; il plugin Kotlin; CastServer; la queue di Aves; il segmenter fMP4.

Se funziona, dimostra in modo pulito che MPEG-TS è la strada compatibile con il tuo TV.

Perfetto, FFmpeg è già pronto e include tutto ciò che serve:

FFmpeg 8.1.1 libx264 AAC HLS muxer ffplay

Ora possiamo creare una prova HLS MPEG-TS completamente esterna a Flutter.

  1. Verifica il file MP4 locale

Se hai già scaricato l’MP4 convertito:

ls -lh cast_1000119720.mp4

Se il nome è diverso, sostituiscilo nei comandi successivi.

  1. Genera 15 secondi di HLS MPEG-TS rm -rf hls_ts_test mkdir hls_ts_test

Poi:

ffmpeg
-y
-i cast_1000119720.mp4
-t 15
-c:v libx264
-profile:v high
-level:v 4.1
-preset veryfast
-b:v 5000k
-maxrate 6000k
-bufsize 12000k
-r 30
-g 90
-keyint_min 90
-sc_threshold 0
-c:a aac
-b:a 160k
-ac 2
-ar 48000
-f hls
-hls_time 3
-hls_list_size 0
-hls_playlist_type vod
-hls_segment_type mpegts
-hls_flags independent_segments
-hls_segment_filename 'hls_ts_test/segment_%05d.ts'
hls_ts_test/master.m3u8

Questo dovrebbe produrre una playlist HLS VOD e circa cinque segmenti MPEG-TS da tre secondi. FFmpeg segmenta in corrispondenza dei keyframe, perciò il GOP è impostato a 90 frame, cioè tre secondi a 30 fps.

  1. Controlla i file prodotti ls -lh hls_ts_test

Dovresti trovare qualcosa di simile:

master.m3u8 segment_00000.ts segment_00001.ts segment_00002.ts segment_00003.ts segment_00004.ts

Visualizza la playlist:

cat hls_ts_test/master.m3u8

Deve contenere file .ts, senza init.mp4 e senza EXT-X-MAP.

  1. Verifica localmente ffplay hls_ts_test/master.m3u8

Oppure:

open -a VLC hls_ts_test/master.m3u8

Se video e audio funzionano per tutti i 15 secondi, il test locale è valido.

  1. Avvia il server HTTP con CORS

Crea il server:

cat > hls_cors_server.py <<'PY' from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer import os

ROOT = os.path.abspath("hls_ts_test") PORT = 8000

class Handler(SimpleHTTPRequestHandler): extensions_map = { **SimpleHTTPRequestHandler.extensions_map, ".m3u8": "application/vnd.apple.mpegurl", ".ts": "video/mp2t", }

def end_headers(self):
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header(
        "Access-Control-Expose-Headers",
        "Content-Length, Content-Type, Accept-Ranges",
    )
    self.send_header("Cache-Control", "no-cache")
    super().end_headers()

def do_OPTIONS(self):
    self.send_response(204)
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header(
        "Access-Control-Allow-Methods",
        "GET, HEAD, OPTIONS",
    )
    self.send_header(
        "Access-Control-Allow-Headers",
        "Range",
    )
    self.end_headers()

if name == "main": os.chdir(ROOT) server = ThreadingHTTPServer(("0.0.0.0", PORT), Handler) print(f"Serving {ROOT} on port {PORT}", flush=True) server.serve_forever() PY

Avvialo:

python3 hls_cors_server.py

Lascialo in esecuzione.

  1. Recupera l’IP Wi-Fi del Mac

In un secondo terminale:

ipconfig getifaddr en0

Se non restituisce nulla:

ipconfig getifaddr en1

Supponendo che restituisca 192.168.1.50, verifica:

curl -I
'http://192.168.1.50:8000/master.m3u8'

e:

curl -I
'http://192.168.1.50:8000/segment_00000.ts'

Il primo deve riportare:

Content-Type: application/vnd.apple.mpegurl Access-Control-Allow-Origin: *

Il secondo:

Content-Type: video/mp2t Access-Control-Allow-Origin: *

Google Cast supporta HLS e il contenitore MP2T, quindi questa prova isola con precisione la compatibilità del Default Media Receiver con HLS MPEG-TS.

  1. Passaggio successivo

Quando questi controlli sono riusciti, installiamo catt, individuiamo il televisore e inviamo direttamente:

http://IP_DEL_MAC:8000/master.m3u8

senza coinvolgere Flutter, Media3 o il server di Aves.

Perfetto, l’output è corretto: FFmpeg ha generato una playlist HLS MPEG-TS di circa 15 secondi con 5 segmenti autonomi da circa 3 secondi ciascuno. Ora verifichiamo la playlist e la proviamo direttamente sul TV, senza Flutter.

  1. Controlla la playlist cat hls_ts_test/master.m3u8

Dovrebbe contenere una struttura simile:

#EXTM3U #EXT-X-VERSION:6 #EXT-X-TARGETDURATION:3 #EXT-X-MEDIA-SEQUENCE:0 #EXT-X-PLAYLIST-TYPE:VOD #EXT-X-INDEPENDENT-SEGMENTS #EXTINF:3.000000, segment_00000.ts ... #EXT-X-ENDLIST

Non devono comparire:

#EXT-X-MAP init.mp4 .m4s

  1. Provalo localmente open -a VLC hls_ts_test/master.m3u8

Verifica che video e audio funzionino per tutti i 15 secondi.

  1. Avvia il server HTTP con CORS

Se hai già creato hls_cors_server.py, avvialo dalla directory che contiene hls_ts_test:

python3 hls_cors_server.py

Dovrebbe mostrare:

Serving .../hls_ts_test on port 8000

Lascialo aperto.

  1. Recupera l’IP Wi-Fi del Mac

In un secondo terminale:

ipconfig getifaddr en0

Se non restituisce nulla:

ipconfig getifaddr en1

Supponendo che restituisca, per esempio:

192.168.1.50

l’URL sarà:

http://192.168.1.50:8000/master.m3u8

  1. Verifica dal Mac

Sostituisci l’IP con quello effettivo:

curl -I
'http://192.168.1.50:8000/master.m3u8'

Devi vedere:

Content-Type: application/vnd.apple.mpegurl Access-Control-Allow-Origin: *

Poi:

curl -I
'http://192.168.1.50:8000/segment_00000.ts'

Devi vedere:

Content-Type: video/mp2t Access-Control-Allow-Origin: *

Google Cast supporta HLS e il contenitore MPEG-TS/MP2T, quindi questo è il formato giusto per verificare la compatibilità con il Default Media Receiver.

  1. Installa e usa catt

Se non lo hai già:

brew install pipx pipx ensurepath pipx install catt

Poi riapri il terminale oppure esegui:

source ~/.zshrc

Trova il dispositivo:

catt scan

Quindi invia la playlist, usando il nome esatto del TV:

catt -d 'NOME TV' cast
'http://192.168.1.50:8000/master.m3u8'

catt può inviare URL multimediali direttamente a un dispositivo Cast.

Cosa osservare

Nel terminale del server dovresti vedere:

GET /master.m3u8 GET /segment_00000.ts GET /segment_00001.ts GET /segment_00002.ts

Se il TV riproduce tutti i 15 secondi e avanza tra i segmenti, avremo dimostrato che:

Default Media Receiver

  • HLS MPEG-TS = compatibile

A quel punto l’implementazione Android del muxer MPEG-TS avrà senso.

Perfetto, la playlist è corretta per una prova HLS MPEG-TS VOD:

5 segmenti da 3 secondi durata complessiva di 15 secondi segmenti .ts nessun init.mp4 nessun EXT-X-MAP playlist chiusa con EXT-X-ENDLIST

Ora testiamola direttamente sul televisore.

  1. Prova locale con VLC open -a VLC hls_ts_test/master.m3u8

Verifica che video e audio funzionino per tutti i 15 secondi.

  1. Avvia il server HTTP con CORS

Dalla directory che contiene hls_ts_test:

python3 hls_cors_server.py

Dovresti vedere:

Serving .../hls_ts_test on port 8000

Lascia questo terminale aperto.

  1. Recupera l’IP Wi-Fi del Mac ipconfig getifaddr en0

Se non restituisce nulla:

ipconfig getifaddr en1

Supponendo che l’IP sia 192.168.1.50, verifica la playlist:

curl -I
'http://192.168.1.50:8000/master.m3u8'

Deve includere:

Content-Type: application/vnd.apple.mpegurl Access-Control-Allow-Origin: *

Controlla anche un segmento:

curl -I
'http://192.168.1.50:8000/segment_00000.ts'

Deve includere:

Content-Type: video/mp2t Access-Control-Allow-Origin: *

Google Cast dichiara il supporto per HLS e per il contenitore MPEG-TS/MP2T, quindi questa prova è adatta a verificare la compatibilità del receiver predefinito.

  1. Installa catt, se necessario

Verifica prima:

catt --version

Se non è installato:

brew install pipx pipx ensurepath pipx install catt

Poi ricarica la shell:

source ~/.zshrc

  1. Trova il dispositivo Cast catt scan

Prendi nota del nome esatto, per esempio:

TV Salotto

  1. Invia la playlist al TV catt -d 'TV Salotto' cast
    'http://192.168.1.50:8000/master.m3u8'

Sostituisci:

TV Salotto con il nome restituito da catt scan 192.168.1.50 con l’IP reale del Mac

catt consente di inviare URL multimediali direttamente a un dispositivo Cast.

  1. Cosa osservare

Nel terminale del server dovrebbero comparire richieste simili:

GET /master.m3u8 GET /segment_00000.ts GET /segment_00001.ts GET /segment_00002.ts GET /segment_00003.ts GET /segment_00004.ts

Test riuscito

Se il TV riproduce i 15 secondi e richiede tutti i segmenti:

Default Media Receiver

  • HLS MPEG-TS = compatibile

A quel punto possiamo procedere con il prototipo Android del muxer MPEG-TS.

Test fallito

Se richiede ripetutamente solo:

segment_00000.ts

oppure non richiede alcun segmento, controlliamo l’output di catt e del server prima di modificare Flutter.

Il prossimo dato utile è quindi l’output di:

catt scan

Nessun problema. Crealo nella cartella che contiene hls_ts_test, poi avvialo da lì. Questo server assegna i MIME corretti e aggiunge gli header CORS richiesti dal test Cast.

  1. Crea hls_cors_server.py

Dalla directory in cui vedi:

hls_ts_test/

esegui:

cat > hls_cors_server.py <<'PY' from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer import os

ROOT = os.path.abspath("hls_ts_test") PORT = 8000

class HlsHandler(SimpleHTTPRequestHandler): extensions_map = { **SimpleHTTPRequestHandler.extensions_map, ".m3u8": "application/vnd.apple.mpegurl", ".ts": "video/mp2t", }

def end_headers(self):
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header(
        "Access-Control-Expose-Headers",
        "Content-Length, Content-Type, Accept-Ranges",
    )
    self.send_header("Cache-Control", "no-cache")
    super().end_headers()

def do_OPTIONS(self):
    self.send_response(204)
    self.send_header("Access-Control-Allow-Origin", "*")
    self.send_header(
        "Access-Control-Allow-Methods",
        "GET, HEAD, OPTIONS",
    )
    self.send_header(
        "Access-Control-Allow-Headers",
        "Range",
    )
    self.end_headers()

if name == "main": if not os.path.isdir(ROOT): raise SystemExit(f"Directory non trovata: {ROOT}")

os.chdir(ROOT)

server = ThreadingHTTPServer(
    ("0.0.0.0", PORT),
    HlsHandler,
)

print(
    f"Serving {ROOT} on http://0.0.0.0:{PORT}",
    flush=True,
)

server.serve_forever()

PY

  1. Verifica che esista ls -lh hls_cors_server.py

Controlla anche che la directory sia nella posizione corretta:

ls -lh hls_ts_test

  1. Avvia il server python3 hls_cors_server.py

Dovresti vedere:

Serving /percorso/completo/hls_ts_test on http://0.0.0.0:8000

Lascia questo terminale aperto.

Se macOS mostra la richiesta di autorizzazione per accettare connessioni in ingresso, premi Consenti.

  1. Recupera l’IP del Mac

In un altro terminale:

ipconfig getifaddr en0

Se non mostra nulla:

ipconfig getifaddr en1

Puoi anche usare:

route -n get default
| grep interface

e poi passare il nome dell’interfaccia a:

ipconfig getifaddr NOME_INTERFACCIA

  1. Verifica il server

Supponendo che l’IP del Mac sia 192.168.1.50:

curl -I
'http://192.168.1.50:8000/master.m3u8'

Devi vedere:

HTTP/1.0 200 OK Content-Type: application/vnd.apple.mpegurl Access-Control-Allow-Origin: *

Poi verifica il segmento:

curl -I
'http://192.168.1.50:8000/segment_00000.ts'

Deve mostrare:

HTTP/1.0 200 OK Content-Type: video/mp2t Access-Control-Allow-Origin: *

  1. Prova prima in VLC via rete open -a VLC
    'http://192.168.1.50:8000/master.m3u8'

Usa il vero IP del Mac. Se VLC riproduce tutti i 15 secondi, il server è configurato correttamente.

Dopo potrai eseguire:

catt scan

e inviare l’URL al televisore.

Esatto: stai eseguendo lo script da dentro hls_ts_test, mentre lo script aggiunge già hls_ts_test al percorso. Perciò cerca erroneamente:

.../hls_ts_test/hls_ts_test

Hai due soluzioni.

Soluzione rapida

Torna alla cartella superiore:

cd ..

Verifica:

pwd ls -lh hls_ts_test ls -lh hls_cors_server.py

Poi avvia:

python3 hls_cors_server.py

Dovrebbe mostrare:

Serving /Volumes/terrain/aves_mio0.70/hls_ts_test on http://0.0.0.0:8000

Soluzione migliore: rendere lo script indipendente dalla cartella corrente

Sostituisci:

ROOT = os.path.abspath("hls_ts_test")

con:

SCRIPT_DIR = os.path.dirname(os.path.abspath(file)) ROOT = os.path.join(SCRIPT_DIR, "hls_ts_test")

Puoi applicare la modifica automaticamente:

python3 - <<'PY' from pathlib import Path

path = Path("hls_cors_server.py") text = path.read_text(encoding="utf-8")

text = text.replace( 'ROOT = os.path.abspath("hls_ts_test")', 'SCRIPT_DIR = os.path.dirname(os.path.abspath(file))\n' 'ROOT = os.path.join(SCRIPT_DIR, "hls_ts_test")', )

path.write_text(text, encoding="utf-8") print("[OK] server aggiornato") PY

Questa operazione va eseguita dalla cartella in cui si trova hls_cors_server.py.

Poi avvia:

python3 hls_cors_server.py

Se vuoi tenere lo script dentro hls_ts_test

Se invece sia lo script sia i file HLS sono già dentro:

/Volumes/terrain/aves_mio0.70/hls_ts_test

imposta semplicemente:

ROOT = os.path.dirname(os.path.abspath(file))

Oppure avvia al volo un server senza script, dalla directory hls_ts_test:

python3 -m http.server 8000 --bind 0.0.0.0

Quest’ultima variante può non assegnare tutti i MIME e gli header CORS desiderati, quindi per il test Cast è preferibile lo script dedicato.

Una volta che compare:

Serving ... on http://0.0.0.0:8000

lascia il terminale aperto e recupera l’IP del Mac con:

ipconfig getifaddr en0

Perfetto. Con l’IP del Mac 192.168.1.2, l’URL del test HLS è:

http://192.168.1.2:8000/master.m3u8

  1. Assicurati che il server sia attivo

Nel terminale del server devi vedere qualcosa come:

Serving .../hls_ts_test on http://0.0.0.0:8000

Lascialo aperto.

  1. Verifica playlist e segmento

In un altro terminale:

curl -I 'http://192.168.1.2:8000/master.m3u8'

Deve comparire:

Content-Type: application/vnd.apple.mpegurl Access-Control-Allow-Origin: *

Poi:

curl -I 'http://192.168.1.2:8000/segment_00000.ts'

Deve comparire:

Content-Type: video/mp2t Access-Control-Allow-Origin: *

  1. Verifica via rete con VLC open -a VLC
    'http://192.168.1.2:8000/master.m3u8'

Se riproduce tutti i 15 secondi, il server è raggiungibile correttamente.

  1. Individua il televisore con catt catt scan

Prendi il nome esatto del dispositivo. Poi invia la playlist:

catt -d 'NOME ESATTO TV' cast
'http://192.168.1.2:8000/master.m3u8'

Se hai un solo dispositivo Cast, puoi anche provare:

catt cast
'http://192.168.1.2:8000/master.m3u8'

  1. Osserva il terminale del server

Se il Default Media Receiver è compatibile con HLS MPEG-TS, dovresti vedere:

GET /master.m3u8 GET /segment_00000.ts GET /segment_00001.ts GET /segment_00002.ts GET /segment_00003.ts GET /segment_00004.ts

Se invece ripete solo segment_00000.ts, incolla l’output del server e di catt. Il test è importante perché Google Cast dichiara supporto per HLS e il contenitore MP2T.

Perfetto, il server è configurato correttamente:

Playlist: application/vnd.apple.mpegurl Segmenti: video/mp2t CORS: Access-Control-Allow-Origin: *

Ora facciamo la prova diretta sul televisore.

  1. Prova prima via rete con VLC open -a VLC
    'http://192.168.1.2:8000/master.m3u8'

Se riproduce tutti i 15 secondi, l’URL di rete è valido.

  1. Verifica se catt è installato catt --version

Se il comando non esiste:

brew install pipx pipx ensurepath pipx install catt

Poi:

source ~/.zshrc

  1. Cerca i dispositivi Cast catt scan

Annota il nome esatto del televisore.

  1. Invia l’HLS MPEG-TS

Sostituisci NOME TV con il nome restituito da catt scan:

catt -d 'NOME TV' cast
'http://192.168.1.2:8000/master.m3u8'

Se hai un solo dispositivo puoi provare:

catt cast
'http://192.168.1.2:8000/master.m3u8'

  1. Osserva il server

Nel terminale dove gira hls_cors_server.py, l’esito positivo dovrebbe mostrare richieste sequenziali:

GET /master.m3u8 GET /segment_00000.ts GET /segment_00001.ts GET /segment_00002.ts GET /segment_00003.ts GET /segment_00004.ts

Se il TV riproduce tutti i 15 secondi, avremo dimostrato che il Default Media Receiver è compatibile con:

HLS + MPEG-TS + H.264 + AAC

Google Cast dichiara il supporto sia per HLS sia per il contenitore MP2T.

Se invece non parte, incollami:

catt scan

l’output del comando catt cast e le richieste comparse nel terminale del server.