Problemas de script de transcodificação MKV para MP4

1

Ok, esse aqui me faz coçar a cabeça - especialmente porque sou um nOOb de script, e minha experiência * nix é básica para dizer o mínimo.

Resumo

É necessário identificar por que o script de shell para conversão de arquivadores de um contêiner de mídia para outro está gerando erros e problemas.

Script

Eu tenho um script de shell fornecido por um amigo. O script é usado em uma máquina Ubuntu 10.10 para converter arquivos de vídeo MKV para MP4 (MPEG-4). O roteiro em questão é o seguinte (perdoe a falta de comentários):

#!/usr/bin/env bash

if [ -f $1 ] ; then
    filename=$(basename $1)
    extension=${filename##*.}
    name=${filename%.*}
    fname=$1
    video='mediainfo --Inform=Video\;%ID% "${fname}"'
    audio='mediainfo --Inform=Audio\;%ID% "${fname}"'
    fps='mediainfo --Inform=Video\;%FrameRate% "${fname}"'
    'mkvextract tracks ${fname} 1:${name}.h264 2:${name}.ac3'
    'a52dec ${name}.ac3 -o wavdolby > ${name}.wav'
    'faac ${name}.wav -o ${name}.m4a'
    'MP4Box -add ${name}.m4a -add ${name}.h264 -fps $fps ${name}.mp4'
    'rm ${name}.m4a ${name}.ac3 ${name}.h264 ${name}.wav'
fi

Problema

pula erros ao executar a52dec

O primeiro erro ocorre apenas em arquivos MKV selecionados, onde é executada a52dec como parte do processo de conversão de áudio.

O que acontece é que um erro de pulo continua aparecendo repetidamente na janela do console / terminal. O processo a52dec criou o nome do arquivo esperado (filename.wav), mas continua gerando essas mensagens ignoradas e não prossegue mais (apesar de ter saído por meia hora em um ponto apenas para ver se o problema ocorreria)

Olhando para a saída do Mediainfo em alguns arquivos diferentes, parece que as coisas estão se soltando onde o arquivo inclui áudio de 5.1 canais. É claro que não tenho idéia de como superar esse problema.

IsoMedia: comando não encontrado

Isso acontece o tempo todo quando o script termina a execução, o que, para este n00b, sugere que não é possível encontrar o aplicativo em questão.

No entanto, eu não consigo encontrar este pacote, ou se parte de um pacote maior que um é para instalar.

Mais confuso, esse arquivo não é chamado em nenhum ponto durante o script e só é chamado depois que o comando rm para limpeza é executado.

Informações adicionais

Exemplo de saída do Mediainfo para um arquivo MKV que transcodifica sem problemas

General
Unique ID                        : 233323168834975742075458986504469215458 (0xAF886862D1B0BB1B9427E04C90A1F8E2)
Complete name                    : \192.168.2.5\video\sorted\CSI NY\CSI.New.York.S07E10.720p.HDTV.X264-DIMENSION.mkv
Format                           : Matroska
File size                        : 1.09 GiB
Duration                         : 41mn 30s
Overall bit rate                 : 3 768 Kbps
Encoded date                     : UTC 2010-12-03 20:40:51
Writing application              : mkvmerge v3.1.0 ('Happy up here') built on Jan 19 2010 12:09:24
Writing library                  : libebml v0.7.9 + libmatroska v0.8.1

Video
ID                               : 1
Format                           : AVC
Format/Info                      : Advanced Video Codec
Format profile                   : [email protected]
Format settings, CABAC           : Yes
Format settings, ReFrames        : 8 frames
Format settings, GOP             : M=6, N=12
Codec ID                         : V_MPEG4/ISO/AVC
Duration                         : 41mn 30s
Bit rate                         : 3 381 Kbps
Width                            : 1 280 pixels
Height                           : 720 pixels
Display aspect ratio             : 16:9
Frame rate                       : 23.976 fps
Color space                      : YUV
Chroma subsampling               : 4:2:0
Bit depth                        : 8 bits
Scan type                        : Progressive
Bits/(Pixel*Frame)               : 0.153
Stream size                      : 982 MiB (88%)
Writing library                  : x264 core 110 r1804 e89c4cf
Encoding settings                : cabac=1 / ref=8 / deblock=1:0:0 / analyse=0x3:0x113 / me=umh / subme=9 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=1 / me_range=24 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=0 / chroma_qp_offset=-2 / threads=12 / sliced_threads=0 / nr=0 / decimate=1 / interlaced=0 / constrained_intra=0 / bframes=5 / b_pyramid=2 / b_adapt=1 / b_bias=0 / direct=1 / weightb=1 / open_gop=0 / weightp=2 / keyint=250 / keyint_min=23 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=2pass / mbtree=1 / bitrate=3381 / ratetol=1.0 / qcomp=0.60 / qpmin=0 / qpmax=51 / qpstep=4 / cplxblur=20.0 / qblur=0.5 / ip_ratio=1.40 / aq=1:1.00
Language                         : English

Audio
ID                               : 2
Format                           : AC-3
Format/Info                      : Audio Coding 3
Mode extension                   : CM (complete main)
Codec ID                         : A_AC3
Duration                         : 41mn 30s
Bit rate mode                    : Constant
Bit rate                         : 384 Kbps
Channel(s)                       : 2 channels
Channel positions                : Front: L R
Sampling rate                    : 48.0 KHz
Bit depth                        : 16 bits
Compression mode                 : Lossy
Stream size                      : 114 MiB (10%)

Exemplo de saída do Mediainfo para um arquivo MKV que causa problemas de a52dec

General
Unique ID                        : 173353892635048029459501626055714892286 (0x826ABECAAEC6D2638DD0EC376D6369FE)
Complete name                    : \192.168.2.5\video\sorted\Conan\conan.2010.11.25.jim.parsons.720p.hdtv.x264-bff.mkv
Format                           : Matroska
File size                        : 1.09 GiB
Duration                         : 42mn 1s
Overall bit rate                 : 3 720 Kbps
Encoded date                     : UTC 2010-11-26 05:45:43
Writing application              : mkvmerge v3.1.0 ('Happy up here') built on Jan 19 2010 12:09:24
Writing library                  : libebml v0.7.9 + libmatroska v0.8.1

Video
ID                               : 2
Format                           : AVC
Format/Info                      : Advanced Video Codec
Format profile                   : [email protected]
Format settings, CABAC           : Yes
Format settings, ReFrames        : 3 frames
Codec ID                         : V_MPEG4/ISO/AVC
Duration                         : 42mn 1s
Bit rate                         : 3 272 Kbps
Width                            : 1 280 pixels
Height                           : 720 pixels
Display aspect ratio             : 16:9
Frame rate                       : 29.970 fps
Color space                      : YUV
Chroma subsampling               : 4:2:0
Bit depth                        : 8 bits
Scan type                        : Progressive
Bits/(Pixel*Frame)               : 0.118
Stream size                      : 961 MiB (86%)
Writing library                  : x264 core 85 r1442tw
Encoding settings                : cabac=1 / ref=3 / deblock=1:0:0 / analyse=0x3:0x113 / me=hex / subme=6 / psy=1 / psy_rd=1.00:0.00 / mixed_ref=0 / me_range=16 / chroma_me=1 / trellis=1 / 8x8dct=1 / cqm=0 / deadzone=21,11 / fast_pskip=1 / chroma_qp_offset=-2 / threads=30 / sliced_threads=0 / nr=0 / decimate=1 / mbaff=0 / constrained_intra=0 / bframes=6 / b_pyramid=1 / b_adapt=1 / b_bias=0 / direct=1 / wpredb=1 / wpredp=0 / keyint=240 / keyint_min=24 / scenecut=40 / intra_refresh=0 / rc_lookahead=40 / rc=2pass / mbtree=1 / bitrate=3272 / ratetol=1.0 / qcomp=0.60 / qpmin=10 / qpmax=51 / qpstep=4 / cplxblur=20.0 / qblur=0.5 / ip_ratio=1.40 / aq=1:1.00
Language                         : English

Audio
ID                               : 1
Format                           : AC-3
Format/Info                      : Audio Coding 3
Mode extension                   : CM (complete main)
Codec ID                         : A_AC3
Duration                         : 42mn 1s
Bit rate mode                    : Constant
Bit rate                         : 448 Kbps
Channel(s)                       : 6 channels
Channel positions                : Front: L C R, Side: L R, LFE
Sampling rate                    : 48.0 KHz
Bit depth                        : 16 bits
Compression mode                 : Lossy
Stream size                      : 135 MiB (12%)
    
por thewinchester 25.04.2011 / 17:51

3 respostas

1

Olá71 provocou um pensamento com seu comentário sobre o ffmpeg e encontrei minha resposta depois de alguma pesquisa adicional.

Uma cópia do código de sucesso para converter o arquivo é a seguinte. Também falha um pouco mais quando um formato de áudio estranho é usado.

(Comentários adicionados para facilitar a compreensão)

#!/bin/bash


# Evaluate the file passed to the script for information relevant to the process
find . -type f | grep .mkv$ | while read file
do
directory='dirname "$file"'
title='basename "$file" .mkv'

# Check the audio track used in the files
AC3='mkvinfo "$file" | grep AC3' #check if it's AC3 audio or DTS
AAC='mkvinfo "$file" | grep AAC'
order='mkvinfo "$file" | grep "Track type" | sed 's/.*://' | head -n 1 | tr -d " "' #check if the video track is first or the audio track

# Start processing
# If video is the first track
if [ "$order" = "video" ]; then
  fps='mkvinfo "$file" | grep duration | sed 's/.*(//' | sed 's/f.*//' | head -n 1' #store the fps of the video track

# If audio is encoded in AC3
  if [ -n "$AC3" ]; then
   mkvextract tracks "$file" 1:"${title}".264 2:"${title}".ac3
   ffmpeg -i "${title}".ac3 -acodec libfaac -ab 576k "${title}".aac
#  mplayer -ao pcm:file="${title}".wav:fast "${title}".ac3
#  faac -o "${title}".aac "${title}".wav


# If audio is encoded in AAC
  elif [ -n "$AAC" ]; then
   mkvextract tracks "$file" 1:"${title}".264 2:"${title}".aac

# If encoded in DTS or something else
  else
   mkvextract tracks "$file" 1:"${title}".264 2:"${title}".dts
   ffmpeg -i "${title}".dts -acodec libfaac -ab 576k "${title}".aac
  fi
else

# If video is not the first track
  fps='mkvinfo "$file" | grep duration | sed 's/.*(//' | sed 's/f.*//' | tail -n 1'
  if [ -n "$AC3" ]; then
   mkvextract tracks "$file" 1:"${title}".ac3 2:"${title}".264
   ffmpeg -i "${title}".ac3 -acodec libfaac -ab 576k "${title}".aac
  # mplayer -ao pcm:file="${title}".wav:fast "${title}".ac3
  # faac -o "${title}".aac "${title}".wav
  elif [ -n "$AAC" ]; then
   mkvextract tracks "$file" 1:"${title}".264 2:"${title}".aac
  else
   mkvextract tracks "$file" 1:"${title}".dts 2:"${title}".264
   ffmpeg -i "${title}".dts -acodec libfaac -ab 576k "${title}".aac
  fi
fi
MP4Box -new "${directory}/${title}".mp4 -add "${title}".264 -add "${title}".aac -fps $fps
rm -f "$title".aac "$title".dts "$title".ac3 "$title".264 "${title}".wav
# if [ -f "${directory}/${title}".mp4 ]; then
# rm -f "$file"
# fi
done
    
por 26.04.2011 / 05:10
3

Script Remuxing de MKV para MP4

Isso é baseado no script do thewinchester postado em sua resposta aqui. Eu comecei com o dele e ele acabou se transformando em uma reescrita da maior parte dele, mas o conceito é o mesmo.

A função básica é pegar um arquivo MKV contendo vídeo h.264 e algum áudio e convertê-lo em um arquivo MP4 / M4V.

Meu objetivo é tornar os arquivos resultantes compatíveis com o iPad e o AppleTV, mas ele deve funcionar com qualquer coisa que possa lidar com arquivos MP4 / M4V. O vídeo não é transcodificado, por isso a qualidade permanece a mesma, o áudio é convertido se necessário, mas faixas de maior qualidade são mantidas, se possível.

Alterações

Uma lista parcial das alterações que fiz:

  • Como gerenciar vários arquivos ou diretórios transmitidos como argumentos
  • Usa (e requer) NeroAAC de qualidade superior para codificar áudio AAC de AC3 ou DTS
  • Como gerenciar várias faixas de áudio de acordo com o padrão AppleTV para permitir a reprodução adequada e o som surround na AppleTV:
    • AAC estéreo de 160kB / s
    • (Opcional) AC-3 (normalmente som surround) como segunda faixa, desativado
  • Convertendo DTS em AC-3
  • Manipulando várias faixas, independentemente do pedido (por exemplo, AAC, Video, AC3)
  • Várias alterações de codificação para facilitar a modificação posterior

Requisitos

O script requer o NeroAAC acima mencionado, bem como Aften (codificação AC3) e libdca / dcadec (decodificação DTS). Assim como no script original, o ffmpeg também é necessário.

Problemas conhecidos

O script é bastante à prova de balas - se ele se depara com algo com o qual ele não consegue lidar, ele normalmente é ignorado ou desiste. Os arquivos originais são deixados intactos, portanto, há pouca ou nenhuma chance de perda de dados.

Eu usei isso em muitas das minhas bibliotecas de mídia e muitas das mudanças foram para corrigir erros que eu encontrei.

Dito isto, há algumas coisas a ter em conta e espaço para melhorias:

  • Manipulando várias faixas de áudio do mesmo tipo - 1 AC3 e 1 AAC é bom, mas 2 faixas AAC não funcionam. Isso não deve acontecer com frequência, mas tenha isso em mente.
  • Não há suporte para faixas que não sejam de áudio / vídeo. Legendas, capítulos e obras de arte são todos ignorados.
  • Nenhuma detecção de som surround AAC. O script copia qualquer faixa AAC, não vai mixar para baixo para estéreo. Tecnicamente para suporte a iPad e AppleTV, a faixa principal de áudio deve ser estéreo AAC, mas acho que na maioria dos casos um iPad ou AppleTV pode lidar com isso normalmente.

Codifique e use

Estou postando aqui esperando que alguém ache útil - sinta-se à vontade para usar e modificar como achar melhor para usos não comerciais. Se você chegar a uma modificação interessante, pode ser bom se você a compartilhou aqui ou em outro lugar.

#!/bin/bash

#Close stdin - avoid accidental keypresses causing problems
exec 0>&-

# Find MKV files
for file in "$@";
do
  find "$file" -type f -not -name ".*" | grep .mkv$ | while read file
  do
    fileProper=$(readlink -f "$file") # full path of file
    pathNoExt=${fileProper%.*} # full path minus extension

    #Check if M4V already exists
    if [ -f "$pathNoExt".m4v ]; then
      echo "M4V already exists, stopping"
    else
      # Get number of tracks
      numberOfTracks='mkvmerge -i "$fileProper" | grep "Track ID" | wc -l'
      echo "Found $numberOfTracks Tracks"

      # Set base extraction command
      extractCmd+=(mkvextract tracks "$fileProper")

      # Determine type of tracks
      for (( i=1; i<=$numberOfTracks; i++ ))
      do
         trackType='mkvmerge -i "$fileProper" | grep "Track ID $i" | sed -e 's/^.*: //''
         if [[ "$trackType" == *video* ]]; then
            echo "Track $i is Video"
            extractCmd+=( $i:"$pathNoExt".264)
            fps='mkvinfo "$fileProper" | grep duration | sed -e 's/.*(//' -e 's/f.*//' | sed -n ${i}p'
         elif [[ "$trackType" == "audio (A_AAC)" ]]; then
            echo "Track $i is AAC"
            extractCmd+=( $i:"$pathNoExt".aac)
         elif [[ "$trackType" == "audio (A_AC3)" ]]; then
            echo "Track $i is AC3"
            extractCmd+=( $i:"$pathNoExt".ac3)
         elif [[ "$trackType" == "audio (A_DTS)" ]]; then
            echo "Track $i is DTS"
            extractCmd+=( $i:"$pathNoExt".dts)
         fi
         # Insert cases for handling other audio and non-AV tracks here
       done

        "${extractCmd[@]}" # Extract Tracks

        # Check files and encode audio if neccessary
        if [ -f "$pathNoExt".264 ]; then
            # Video file exists
            mp4BoxCmd+=(MP4Box -new "$pathNoExt".m4v -add "$pathNoExt".264 -fps $fps)
            if [ -f "$pathNoExt".aac ]; then
                # AAC exists
                mp4BoxCmd+=( -add "$pathNoExt".aac)
                if [ -f "$pathNoExt".ac3 ]; then
                    mp4BoxCmd+=( -add "$pathNoExt".ac3:disable)
                elif [ -f "$pathNoExt".dts ]; then
                    # Encode DTS to AC3
                    dcadec -o wavall "$pathNoExt".dts | aften -v 0 - "$pathNoExt".ac3
                    mp4BoxCmd+=( -add "$pathNoExt".ac3:disable)
                fi
            else # Encode AAC from AC3 or DTS
                if [ -f "$pathNoExt".ac3 ]; then
                    ffmpeg -i "$pathNoExt".ac3 -acodec pcm_s16le -ac 2 -f wav - | neroAacEnc -lc -br 160000 -ignorelength -if - -of "$pathNoExt".aac
                    mp4BoxCmd+=( -add "$pathNoExt".aac -add "$pathNoExt".ac3:disable)
                elif [ -f "$pathNoExt".dts ]; then
                  ffmpeg -i "$pathNoExt".dts -acodec pcm_s16le -ac 2 -f wav - | neroAacEnc -lc -br 160000 -ignorelength -if - -of "$pathNoExt".aac
                    # Encode DTS to AC3
                    dcadec -o wavall "$pathNoExt".dts | aften -v 0 - "$pathNoExt".ac3
                    mp4BoxCmd+=( -add "$pathNoExt".aac -add "$pathNoExt".ac3:disable)
                else
                    echo "Warning: no audio file found"
                fi
            fi
            # Create m4v
            "${mp4BoxCmd[@]}"
        else
            echo "Error: no video file found"
        fi
  #remove temporary track files
  rm -f "$pathNoExt".aac "$pathNoExt".dts "$pathNoExt".ac3 "$pathNoExt".264 "$pathNoExt".wav
  fi
 done
done
    
por 10.12.2011 / 00:22
1

A ferramenta FFmpeg pode fazer a maior parte do que é descrito aqui.

ffmpeg -i input.mkv -c copy output.mp4

Em um loop for (remux todo * .mkv em um diretório):

for f in *.mkv; do ffmpeg -i "$f" -c copy "${f/%mkv/mp4}"; done

... funcionará na maior parte do tempo, já que a maioria dos arquivos MKV terá vídeo h.264 e áudio AAC. Para converter um arquivo que não usa esses:

ffmpeg -i input.mkv -c:v libx264 -crf 23 -preset veryfast -c:a libfdk_aac -vbr 3 output.mp4

Veja o x264 e AAC no wiki do FFmpeg para mais informações.

Se você deseja transcodificar apenas os arquivos que devem ser convertidos, você pode usar um script bash da seguinte forma:

#!/bin/bash
for f in *.mkv
do

##  Detect what audio codec is being used:
audio=$(ffprobe "$f" 2>&1 | sed -n '/Audio:/s/.*: \([a-zA-Z0-9]*\).*//p' | sed 1q)
##  Detect video codec:
video=$(ffprobe "$f" 2>&1 | sed -n '/Video:/s/.*: \([a-zA-Z0-9]*\).*//p' | sed 1q)
##  Set default audio settings (you may need to use a different encoder,
##  since libfdk_aac is not re-distributable)
aopts="-c:a libfdk_aac -vbr 3"
##  Set default video settings:
vopts="-c:v libx264 -crf 22 -preset veryfast"

    case "$audio" in
        aac|alac|mp3|mp2|ac3 )
##  If the audio is one of the MP4-supported codecs,
##  copy the stream instead of transcoding
            aopts="-c:a copy"
            ;;
        "" )
##  If there is no audio stream, don't bother with audio
            aopts="-an"
            ;;
        * )
            ;;
    esac

    case "$video" in
##  If the video stream is one of the MP4-compatible formats,
##  copy the stream
        h264|mpeg4|mpeg2video|mpeg1video )
            vopts="-c:v copy"
            ;;
        "" )
## If no video stream is detected, don't bother with video
            vopts="-vn"
            ;;
        * )
            ;;
    esac

##  This will tell you what is going on; that is,
##  it will echo a line that will make the terminal output
##  easier to follow:
echo -e "\n    \E[1;30mffmpeg -i $f -map 0 $vopts $aopts ${f/%mkv/mp4}\E[0m"

##  And now, to the meat of the thing.
##  Normally you should ALWAYS quote your variables
##  so that spaces in filenames etc will be preserved.
##  But in this case, doing so for $vopts and $aopts
##  would break the ffmpeg command
##  because we WANT the spaces to break up the strings:
ffmpeg -y -i "$f" -map 0 $vopts $aopts "${f/%mkv/mp4}"
done

exit 0
    
por 30.01.2013 / 23:24