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

1524 lines
31 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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.
2. 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
2. 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
3. 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.
4. 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
5. Verifica localmente
ffplay hls_ts_test/master.m3u8
Oppure:
open -a VLC hls_ts_test/master.m3u8
6. 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.
7. 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
8. 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
9. Trova il dispositivo Cast
catt scan
Annota il nome esatto mostrato, per esempio:
TV Salotto
10. 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.
2. 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.
3. 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.
4. 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.
5. 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.
6. 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.
7. 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
2. Provalo localmente
open -a VLC hls_ts_test/master.m3u8
Verifica che video e audio funzionino per tutti i 15 secondi.
3. 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.
4. 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
5. 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.
6. 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.
2. 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.
3. 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.
4. 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
5. Trova il dispositivo Cast
catt scan
Prendi nota del nome esatto, per esempio:
TV Salotto
6. 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.
7. 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
2. Verifica che esista
ls -lh hls_cors_server.py
Controlla anche che la directory sia nella posizione corretta:
ls -lh hls_ts_test
3. 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.
4. 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
5. 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: *
6. 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.
2. 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: *
3. 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.
4. 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'
5. 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.
2. Verifica se catt è installato
catt --version
Se il comando non esiste:
brew install pipx
pipx ensurepath
pipx install catt
Poi:
source ~/.zshrc
3. Cerca i dispositivi Cast
catt scan
Annota il nome esatto del televisore.
4. 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'
5. 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.