AVCONV: pts has no value error

Convertendo nel formato mp4 può verificarsi l’ errore “pts has no value error” ripetuto moltissime volte.

Spiegazione e correzione:

First, a background on why this error exists. AVI does not support variable frame rate video. So somewhere at the start of the file the frame rate is recorded. mp4 does support variable frame rate, so it is required that the duration of each frame is known. In ffmpeg the pts generation for fixed frame rate video is usually handled by the decoder. but by using -codec copy, you are bypassing the decoder.

The solution is specifying -fflags +genpts (must be before the input file is specified with -i).

AVCONV: join mp4 video

la guida contiene alcuni errori:
https://trac.ffmpeg.org/wiki/How%20to%20concatenate%20%28join,%20merge%29%20media%20files

il modo per concatenare più video mp4 (tutti con la stessa codifica) è quello di cambiare il loro “contenitore” in MPEGts (MPEG transport stream) SENZA TRANSCODIFICARE IL FLUSSO !

ottenuti i video MPEGts si possono concatenare con il protocollo “concat” di avconv: qui nasce un problema sul flusso AUDIO se si specifica il bitstream filter aac_adtstoasc che secondo la documentazione sarebbe necessario. invece, se lo si omette, l’ errore non si presenta, ma dopo la concatenazione si ottiene un file con un contenitore diverso da quelli di origine.

vediamo i passaggi:

# conversione del video:
avconv -i R1.mp4 -an -vcodec copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
avconv -i R2.mp4 -an -vcodec copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts

avconv -i "concat:intermediate1.ts|intermediate2.ts" -an -vcodec copy video.mp4

#conversione dell' audio:
avconv -i R1.mp4 -vn -acodec copy -f mpegts audio1.ts
avconv -i R2.mp4 -vn -acodec copy -f mpegts audio2.ts

avconv -i "concat:audio1.ts|audio2.ts" -vn -acodec copy audio.m4a

# riunire i flussi audio e video (mux audio/video):
avconv -i video.mp4 -i audio.m4a -c copy -map 0:v -map 1:a output.mp4

per trattare contemporaneamente audio e video:

avconv -i R1.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate1.ts
avconv -i R2.mp4 -c copy -bsf:v h264_mp4toannexb -f mpegts intermediate2.ts
avconv -i "concat:intermediate1.ts|intermediate2.ts" -c copy video.mp4

come si vede dai parametri di avconv, il flusso non viene ricodificato, ma COPIATO.

C’è però il cambio di container, come detto sopra.
Lo si può vedere con avprobe:

$ avprobe R1.mp4 
avprobe version 11-6:11-2, Copyright (c) 2007-2014 the Libav developers
  built on Oct 19 2014 21:50:10 with gcc 4.9.1 (Debian 4.9.1-15)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'R1.mp4':
  Metadata:
    major_brand     : MSNV
    minor_version   : 512
    compatible_brands: MSNV
    creation_time   : 2014-07-02 11:05:12
  Duration: 00:12:30.00, start: 0.000000, bitrate: 2715 kb/s
    Stream #0.0(eng): Video: h264 (Main), yuv420p, 848x480 [PAR 1:1 DAR 53:30], 2585 kb/s, 25 fps, 25k tbn, 50 tbc (default)
    Metadata:
      creation_time   : 2014-07-02 11:05:12
    Stream #0.1(eng): Audio: aac, 48000 Hz, stereo, fltp, 125 kb/s (default)
    Metadata:
      creation_time   : 2014-07-02 11:05:12
# avprobe output
$ avprobe output.mp4 
avprobe version 11-6:11-2, Copyright (c) 2007-2014 the Libav developers
  built on Oct 19 2014 21:50:10 with gcc 4.9.1 (Debian 4.9.1-15)
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'output.mp4':
  Metadata:
    major_brand     : isom
    minor_version   : 512
    compatible_brands: isomiso2avc1mp41
    encoder         : Lavf56.1.0
  Duration: 00:24:35.96, start: 0.000000, bitrate: 2678 kb/s
    Stream #0.0(und): Video: h264 (Main), yuv420p, 848x480 [PAR 1:1 DAR 53:30], 2546 kb/s, 25 fps, 90k tbn, 50 tbc (default)
    Stream #0.1(eng): Audio: aac, 48000 Hz, stereo, fltp, 128 kb/s (default)
# avprobe output

La stessa cosa si può fare senza passare per i file intermedi: bisogna soltanto creare tante FIFO (named pipe) quanti sono i file mp4 da unire.
Il “trucco” consiste nel mettere le FIFO in attesa dei dati da parte del comando avconv che genera i MPEGts.
Poi si lancia il comando avconv che esegue la concatenazione:

mkfifo temp1 temp2
avconv -i R1.mp4 -c copy -f mpegts -bsf h264_mp4toannexb -y temp1 &
avconv -i R2.mp4 -c copy -f mpegts -bsf h264_mp4toannexb -y temp2 &
avconv -f mpegts -i "concat:temp1|temp2" -c copy output.mp4
rm temp1 temp2

AVCONV e pipe

per convertire un file audio/video con avconv basta scrivere una riga come questa:
avconv -i input.mpg output.mp4

però se si vuole usare un encoder “personalizzato” è possibile inviare l’ output non compresso tramite una pipe. ad esempio:
avconv -i input.m4a -f s32be -af atrim=10:45 pipe: | lame -r --big-endian --bitwidth 32 -ms -q0 --vbr-new -V3 - test.mp3
in cui si può notare che il flusso decompresso nel formato raw PCM signed a 32 bit big-endian viene trimmato tra i 10 e i 45 secondi e poi inviato alla pipe.

lame poi deve essere istruito riguardo al flusso che riceve dallo STDIN (indicato dal carattere “-” come input): si indica “-r –big-endian –bitwidth 32 -ms” per segnalare il formato del flusso raw (32 bit big endian e modalità stereo; signed è di default).

dopodichè viene compresso alla massima qualità e VBR 3.

in modo simile si può operare per i video: decomprimere, trattare il flusso (ad esempio trim o concat) ed inviarlo alla pipe.
riceverlo in stdin indicando tutti i parametri del flusso.

Avconv: aggiungere traccia audio

Per aggiungere (o sostituire) una traccia audio ad un file video, bisogna specificare un file audio in input, oltre al video;
quindi si effettua la mappatura dei “canali”: in avconv si hanno i seguenti canali

  1. audio
  2. video
  3. sottotitoli

Con lo switch -map i:c diciamo che l’ input “i” lo assegniamo al canale “c”.
Per esempio:

avconv -i video.mp4 -i audio.mp3 -vcodec copy -acodec copy -map 0:1 -map 1:0 output.mp4

Il primo input (il video) viene mappato con -map 0:1
il secondo input (l’ audio) viene mappato con -map 1:0

Estrazione fotogrammi con avconv

Se si vuole estrarre fotogrammi ad un rate inferiore a quello del video si ottiene sempre un errore
[mjpeg @ 0x9a18480] Error, Invalid timestamp=0, last=0

Mettendo il parametro -vsync 1 non si presenta più.

Esempio:

avconv -i myvideo.MP4 -vsync 1 -r 0.2 -an -y 'frame%04d.jpg'

Modifica del framerate con avconv (ffmpeg)

I filmati della GoPro sono in MP4 con audio AAC.
Non è possibile modificare direttamente il framerate : bisogna prima decomprimere il video in un formato grezzo (RAW), elaborarlo, e ricomprimerlo come si vuole.
Ma quando si lavora con il formato RAW, bisogna anche inserire manualmente i parametri del video, altrimenti avconv restituisce degli errori come:

[IMGUTILS @ 0xbfd9a704] Picture size 0x0 is invalid
[rawvideo @ 0x8e95ec0] Could not find codec parameters (Video: rawvideo, yuv420p)
[rawvideo @ 0x8e95ec0] Estimating duration from bitrate, this may be inaccurate
pipe:: could not find codec parameters

Quindi bisogna inserire nella riga di comando almeno i parametri –pix_fmt, -vcodec, -s.
Per leggere i valori da inserire, si lancia avconv senza un output:

$ avconv -i video.mp4
[...]
Stream #0.0(eng): Video: h264 (High), yuvj420p, 1280x720
[...]

Quindi costruisco il comando che decomprime il video leggendo i valori restituiti:
(non usare questo esempio: potrebbe uscire un file enorme !)

avconv -i video.mp4 -f rawvideo -pix_fmt yuv420p -vcodec rawvideo -s 1280x720 -y output.tmp

Ora è possibile elaborare il video:

# notare il parametro -r prima del file di input: serve a leggere
# il file di input ad una velocità diversa da quella di default.
avconv -r 10 -f rawvideo -pix_fmt yuv420p -s 1280x720 -i output.tmp -y output.mp4
# se necessario, è possibile specificare un framerate anche per l' output:
avconv -r 10 -f rawvideo -pix_fmt yuv420p -s 1280x720 -i output.tmp -r 30 -y output.mp4

Invece di fare le 2 operazioni di decodifica e ricodifica separatamente, è preferibile usare una pipe.
Quindi riprendo i 2 comandi appena visti e li unisco, usando però lo stdout per scrivere e lo stdin per leggere il video RAW:

avconv -i video.mp4 -f rawvideo -pix_fmt yuv420p -vcodec rawvideo -s 1280x720 pipe:1 | \
avconv -r 10 -f rawvideo -pix_fmt yuv420p -s 1280x720 -i pipe:0 -y output.mp4
# è possibile anche non specificare il file descriptor delle pipe:
# avconv riesce da solo a prendere la pipe giusta
avconv -i video.mp4 -f rawvideo -pix_fmt yuv420p -vcodec rawvideo -s 1280x720 pipe: | \
avconv -r 10 -f rawvideo -pix_fmt yuv420p -s 1280x720 -i pipe: -y output.mp4