Percebi se extraio frames com este comando:
ffmpeg -i sample_nosound.mp4 $filename%03d.jpg
Ele irá extrair depende de fps por padrão. ffmpeg -i sample_nosound.mp4
mostra que este vídeo tem 6 fps, então ele extraiu 1630 arquivos de quadros jpg, que 1630/6 = 271,6 segundos equivalentes à duração total do vídeo de 4:32.
Mas o tamanho total de 1630 quadros jpg é de 13 MB:
$ du -h extracted_jpg_folder
13M extracted_jpg_folder
, enquanto o tamanho do arquivo do mp4 é de 1,8 MB, muito menor que o tamanho total dos quadros:
$ ls -la sample_nosound.mp4
-rw-rw-r-- 1 xiaobai xiaobai 1814889 Feb 13 15:42 'sample_nosound.mp4'
Isso significa que o ffmpeg extrai quadros consultando informações de fps com quadros duplicados.
Portanto, minha pergunta é: como fazer ffmpeg extrair quadros por "quadros armazenados" sem depender de fps?
Espero que eu possa obter o tamanho total dos quadros que é quase equivalente ao tamanho dos arquivos mp4.
Não espero um tamanho de arquivo de correspondência exata, pois o mp4 pode conter alguns metadados.
Saída de ffprobe -i sample_nosound.mp4
:
ffprobe version 3.4.4-0ubuntu0.18.04.1 Copyright (c) 2007-2018 the FFmpeg developers
built with gcc 7 (Ubuntu 7.3.0-16ubuntu3)
configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
WARNING: library configuration mismatch
avcodec configuration: --prefix=/usr --extra-version=0ubuntu0.18.04.1 --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libmysofa --enable-libopenjpeg --enable-libopenmpt --enable-libopus --enable-libpulse --enable-librubberband --enable-librsvg --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxml2 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libdrm --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared --enable-version3 --disable-doc --disable-programs --enable-libopencore_amrnb --enable-libopencore_amrwb --enable-libtesseract --enable-libvo_amrwbenc
libavutil 55. 78.100 / 55. 78.100
libavcodec 57.107.100 / 57.107.100
libavformat 57. 83.100 / 57. 83.100
libavdevice 57. 10.100 / 57. 10.100
libavfilter 6.107.100 / 6.107.100
libavresample 3. 7. 0 / 3. 7. 0
libswscale 4. 8.100 / 4. 8.100
libswresample 2. 9.100 / 2. 9.100
libpostproc 54. 7.100 / 54. 7.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'sample_nosound.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
encoder : Lavf57.83.100
Duration: 00:04:32.00, start: 0.000000, bitrate: 53 kb/s
Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt470bg/bt709/bt709), 640x330 [SAR 1:1 DAR 64:33], 53 kb/s, 6 fps, 6 tbr, 12288 tbn, 12 tbc (default)
Metadata:
handler_name : VideoHandler
Pelo que entendi a pergunta, você deseja extrair os quadros do vídeo. Cada quadro deve ser armazenado em um arquivo separado. Espera-se que a soma dos tamanhos de todos os arquivos corresponda ao tamanho do arquivo do vídeo. Isso é verdade apenas para alguns vídeos específicos. Vou tentar explicar as coisas de forma ampla.
TL;DR
Não é possível extrair quadros de vídeo codificado em h264 com a mesma qualidade visual e tamanho de arquivo.
Os formatos de contêiner de vídeo são confusos
O arquivo de vídeo neste caso é um arquivo MP4. MP4 é um contêiner para dados de vídeo. O tipo de contêiner, no entanto, não diz nada sobre o conteúdo real. Na verdade, muitos tipos diferentes de formatos de vídeo podem residir dentro de um arquivo MP4 – assim como um arquivo zip (ou um arquivo PDF).
Existem vários tipos de vídeo
Um vídeo é uma sequência de imagens. Há muitas maneiras de armazenar essas imagens em um fluxo de vídeo (codificar) e como lê-las posteriormente (decodificar). Os algoritmos são normalmente chamados de codecs .
Tenha em mente que nem todos os codecs fazem compressão. Neste exemplo, h264 é o codec. Por padrão, o codificador h264 calcula a diferença de um quadro para o próximo. No caso de uma pequena diferença, o codificador armazena apenas a diferença. O quadro real é descartado. Apenas o primeiro¹ quadro é armazenado como uma imagem completa. Isso economiza muito espaço e é uma das estratégias de compressão. O decodificador h264 aplicará a diferença armazenada ao quadro anterior, recriando o original.
Como você pode ver, os quadros do seu vídeo dependem um do outro. Se você quer arquivos únicos, você quer que eles sejam independentes. Isso significa que você sempre precisa armazenar as informações completas para cada quadro. Isso significa que você não pode simplesmente pegar os dados existentes e copiá-los para arquivos, mas deve recodificar o vídeo. Ao longo do caminho, a soma dos tamanhos dos arquivos deve aumentar.
Você pode ler os vários tipos de imagem na compactação de vídeo , especificamente os inter-quadros "baseados em diferenças" ou uma visão geral da compactação de vídeo em geral .
h264 não é JPEG
Mesmo se estivermos falando de imagens individuais. O JPEG usa um método de compactação conhecido como DCT . O H.264 usa uma versão semelhante, mas aprimorada. Isso significa que o JPEG não pode compactar tão eficientemente quanto o h264. A propósito, você pode colocar uma imagem compactada h264 em um arquivo usando HEIF (isso se comporta essencialmente como um vídeo de um quadro).
¹Isso não é totalmente verdade, mas quero simplificar por enquanto. Na verdade, é mais como "o primeiro quadro de uma cena". Se você quiser saber os detalhes:
O codificador percebe o início de cenas individuais (na cinematografia, isso geralmente é chamado de "corte"). A diferença de um quadro para outro é muito alta e, portanto, não é boa para compactar. O codificador decide não usar um interquadro "baseado em diferenças". Em vez disso, ele usa a imagem completa (isso é chamado de "intra-quadro", também conhecido como "quadro-chave").
Há também uma razão técnica: apenas para intra-frames você pode pular rapidamente ao procurar pelo vídeo. Consequentemente, os intraquadros também são colocados no fluxo de vez em quando (independentemente do conteúdo de vídeo real). Comumente,
Agora aprendemos muito sobre compressão de vídeo. Este vídeo demonstra algumas das coisas: Devido à corrupção do arquivo, este vídeo perdeu um intra-quadro. O decodificador consegue reproduzi-lo com mais ou menos sucesso. O quadro perdido provavelmente mostrava a mulher olhando para o lado. Agora ela vira a cabeça para trás, o decodificador só tem os dados dos inter-quadros que incluem algumas informações de movimento. Parece que a mulher acabou com o rosto na lateral da cabeça. Enquanto isso, uma pessoa caminha pelo fundo. Essa pessoa não estava presente no intra-quadro perdido e, portanto, parece muito bem.