
Recherche avancée
Médias (91)
-
Head down (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Echoplex (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Discipline (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
Letting you (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
1 000 000 (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
-
999 999 (wav version)
26 septembre 2011, par
Mis à jour : Avril 2013
Langue : English
Type : Audio
Autres articles (38)
-
Personnaliser en ajoutant son logo, sa bannière ou son image de fond
5 septembre 2013, parCertains thèmes prennent en compte trois éléments de personnalisation : l’ajout d’un logo ; l’ajout d’une bannière l’ajout d’une image de fond ;
-
La file d’attente de SPIPmotion
28 novembre 2010, parUne file d’attente stockée dans la base de donnée
Lors de son installation, SPIPmotion crée une nouvelle table dans la base de donnée intitulée spip_spipmotion_attentes.
Cette nouvelle table est constituée des champs suivants : id_spipmotion_attente, l’identifiant numérique unique de la tâche à traiter ; id_document, l’identifiant numérique du document original à encoder ; id_objet l’identifiant unique de l’objet auquel le document encodé devra être attaché automatiquement ; objet, le type d’objet auquel (...) -
Ecrire une actualité
21 juin 2013, parPrésentez les changements dans votre MédiaSPIP ou les actualités de vos projets sur votre MédiaSPIP grâce à la rubrique actualités.
Dans le thème par défaut spipeo de MédiaSPIP, les actualités sont affichées en bas de la page principale sous les éditoriaux.
Vous pouvez personnaliser le formulaire de création d’une actualité.
Formulaire de création d’une actualité Dans le cas d’un document de type actualité, les champs proposés par défaut sont : Date de publication ( personnaliser la date de publication ) (...)
Sur d’autres sites (5874)
-
Bad src image ptrs converting YUV to RGB after H264 decoding with libav and c++
31 octobre 2023, par Sebastian DELLINGI am getting "bad src image ptrs" errors when trying to convert my frames to RGB with sws_scale after decoding frames from a H264 file and cannot figure out wht is going wrong.


I checked what is causing the error and found the
check_image_pointers
function in swscale.c which validates that the planes and line sizes needed for the pixel format (av_pix_fmt_desc_get
) are present in the given data which seems not to be the case with my data.

The written pgm files look ok to me, also replaying the file works.


I printed the corresponding data of my frame. The problem seems that planes 1 and 2 have lines sizes of 0. All 3 of them seem to have data. Plane 0 line size is three times image width which is also confusing to me.


Here is my output :


Have videoStreamIndex 0 codec id: 27
saving frame 1 C:\\tmp\\output-frame-1.pgm colorspace 2 pix_fmt 0 w: 3840 h: 2160
Required:
plane 0 : 0
plane 1 : 1
plane 2 : 2
plane 3 : 0
Present:
Frame plane 0: 1 , 11520
Frame plane 1: 1 , 0
Frame plane 2: 1 , 0
Frame plane 3: 0 , 0
Frame plane 4: 0 , 0
Frame plane 5: 0 , 0
Frame plane 6: 0 , 0
Frame plane 7: 0 , 0



Here the whole code of my application, the issues occurs in method decode :


#include <iostream>
#include <cstring>
#include <cstdio>
#include <cstdint>
#include <string>
#include <iostream>
#include <chrono>

// #include <opencv2></opencv2>highgui.hpp>
// #include <opencv2></opencv2>opencv.hpp>

extern "C"
{

#include <libswscale></libswscale>swscale.h>
#include <libavcodec></libavcodec>avcodec.h>
#include <libavformat></libavformat>avformat.h>
#include <libavfilter></libavfilter>buffersink.h>
#include <libavfilter></libavfilter>buffersrc.h>
#include <libavutil></libavutil>opt.h>
#include <libavutil></libavutil>pixdesc.h>
#include <libavutil></libavutil>display.h>
#include "libavutil/imgutils.h"
}

#define INBUF_SIZE 4096
class H264Decoder
{
public:
 H264Decoder(const std::string &inputFilename, const std::string &outputFilenamePrefix)
 {

 // Open input file
 if (avformat_open_input(&formatContext, inputFilename.c_str(), nullptr, nullptr) != 0)
 {
 throw std::runtime_error("Could not open input file");
 }

 if (avformat_find_stream_info(formatContext, nullptr) < 0)
 {
 throw std::runtime_error("Could not find stream information");
 }

 // Find H.264 video stream
 for (unsigned i = 0; i < formatContext->nb_streams; i++)
 {
 if (formatContext->streams[i]->codecpar->codec_id == AV_CODEC_ID_H264)
 {
 videoStreamIndex = i;
 std::cout << "Have videoStreamIndex " << videoStreamIndex << " codec id: " << formatContext->streams[i]->codecpar->codec_id << std::endl;
 break;
 }
 }

 if (videoStreamIndex == -1)
 {
 throw std::runtime_error("H.264 video stream not found");
 }

 // Initialize codec and codec context
 const AVCodec *codec = avcodec_find_decoder(formatContext->streams[videoStreamIndex]->codecpar->codec_id);
 if (!codec)
 {
 throw std::runtime_error("Codec not found");
 }

 parser = av_parser_init(codec->id);
 if (!parser)
 {
 throw std::runtime_error("parser not found");
 }

 codecContext = avcodec_alloc_context3(codec);
 if (!codecContext)
 {
 throw std::runtime_error("Could not allocate codec context");
 }

 if (avcodec_open2(codecContext, codec, nullptr) < 0)
 {
 throw std::runtime_error("Could not open codec");
 }

 // Initialize frame
 frame = av_frame_alloc();
 frame->format = AV_PIX_FMT_YUV420P;
 if (!frame)
 {
 throw std::runtime_error("Could not allocate frame");
 }

 inputPacket = av_packet_alloc();
 if (!inputPacket)
 {
 throw std::runtime_error("Could not allocate packet");
 }

 inputFilename_ = inputFilename;
 outputFilenamePrefix_ = outputFilenamePrefix;
 }

 void decode()
 {
 char buf[1024];
 int ret;

 ret = avcodec_send_packet(codecContext, inputPacket);
 if (ret < 0)
 {
 fprintf(stderr, "Error sending a packet for decoding\n");
 exit(1);
 }

 while (ret >= 0)
 {
 ret = avcodec_receive_frame(codecContext, frame);
 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
 return;
 else if (ret < 0)
 {
 fprintf(stderr, "Error during decoding\n");
 exit(1);
 }

 /* the picture is allocated by the decoder. no need to
 free it */
 snprintf(buf, sizeof(buf), "%s-%" PRId64 ".pgm", outputFilenamePrefix_.c_str(), codecContext->frame_num);

 std::cout << "saving frame " << codecContext->frame_num << " " << buf << " colorspace " << frame->colorspace << " pix_fmt " << codecContext->pix_fmt << " w: " << frame->width << " h: " << frame->height << std::endl;

 SwsContext *sws_ctx = NULL;

 sws_ctx = sws_getContext(codecContext->width,
 codecContext->height,
 codecContext->pix_fmt,
 codecContext->width,
 codecContext->height,
 AV_PIX_FMT_RGB24,
 SWS_BICUBIC,
 NULL,
 NULL,
 NULL);

 AVFrame *frame2 = av_frame_alloc();
 int num_bytes = av_image_get_buffer_size(AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 32);
 uint8_t *frame2_buffer = (uint8_t *)av_malloc(num_bytes * sizeof(uint8_t));
 av_image_fill_arrays(frame2->data, frame->linesize, frame2_buffer, AV_PIX_FMT_RGB24, codecContext->width, codecContext->height, 32);

 const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(codecContext->pix_fmt);
 std::cout << "Required:" << std::endl;
 for (int i = 0; i < 4; i++)
 {
 int plane = desc->comp[i].plane;
 std::cout << "plane " << i << " : " << plane << std::endl;
 }
 std::cout << "Present:" << std::endl;
 for (int i = 0; i < AV_NUM_DATA_POINTERS; ++i)
 {
 std::cout << "Frame plane " << i << ": " << static_cast<bool>(frame->data[i]) << " , " << frame->linesize[i] << std::endl;
 }

 sws_scale(sws_ctx, frame->data,
 frame->linesize, 0, codecContext->height,
 frame2->data, frame2->linesize);

 // cv::Mat img(frame2->height, frame2->width, CV_8UC3, frame2->data[0]);
 // cv::imshow("Image", img);

 pgm_save(frame->data[0], frame->linesize[0],
 frame->width, frame->height, buf);
 }
 }

 ~H264Decoder()
 {
 avformat_close_input(&formatContext);
 avformat_free_context(formatContext);
 avcodec_free_context(&codecContext);
 av_frame_free(&frame);
 av_packet_free(&inputPacket);
 }

 void readAndDecode()
 {
 FILE *f;
 uint8_t inbuf[INBUF_SIZE + AV_INPUT_BUFFER_PADDING_SIZE];
 uint8_t *data;
 size_t data_size;
 int ret;
 int eof;
 f = fopen(inputFilename_.c_str(), "rb");
 auto start = std::chrono::high_resolution_clock::now();
 do
 {
 /* read raw data from the input file */
 data_size = fread(inbuf, 1, INBUF_SIZE, f);
 if (ferror(f))
 break;
 eof = !data_size;

 /* use the parser to split the data into frames */
 data = inbuf;
 while (data_size > 0 || eof)
 {
 ret = av_parser_parse2(parser, codecContext, &inputPacket->data, &inputPacket->size,
 data, data_size, AV_NOPTS_VALUE, AV_NOPTS_VALUE, 0);
 if (ret < 0)
 {
 fprintf(stderr, "Error while parsing\n");
 exit(1);
 }
 data += ret;
 data_size -= ret;

 if (inputPacket->size)
 {
 decode();
 }
 else if (eof)
 {
 break;
 }
 }
 } while (!eof);
 auto diff = std::chrono::high_resolution_clock::now() - start;
 std::cout << "Decoded " << codecContext->frame_num << " frames in " << std::chrono::duration_cast(diff).count() << " ms" << std::endl;
 }

private:
 AVFormatContext *formatContext = nullptr;
 AVCodecContext *codecContext = nullptr;
 AVCodecParserContext *parser;
 AVFrame *frame = nullptr;
 AVFrame *frameRgb = nullptr;
 AVPacket *inputPacket = nullptr;
 int videoStreamIndex = -1;
 std::string inputFilename_;
 std::string outputFilenamePrefix_;

 static void pgm_save(unsigned char *buf, int wrap, int xsize, int ysize, const char *filename)
 {
 FILE *f = fopen(filename, "wb");
 if (!f)
 {
 std::cout << "Error opening file for saving PGM" << std::endl;
 exit(1);
 }

 fprintf(f, "P5\n%d %d\n%d\n", xsize, ysize, 255);
 for (int i = 0; i < ysize; i++)
 fwrite(buf + i * wrap, 1, xsize, f);

 fclose(f);
 }
};

int main(int argc, char *argv[])
{
 if (argc < 2)
 {
 std::cout << "Please provide input file name as parameter" << std::endl;
 }

 std::string inputFilename = argv[1];
 std::string outputFilenamePrefix = "C:\\tmp\\output-frame";

 try
 {

 H264Decoder decoder(inputFilename, outputFilenamePrefix);
 decoder.readAndDecode();
 }
 catch (const std::exception &e)
 {
 std::cout << "Error: " << e.what() << std::endl;
 return 1;
 }

 return 0;
}
</bool></chrono></iostream></string></cstdint></cstdio></cstring></iostream>


-
Merge file without data loss using FFmpeg inside of WASM
9 septembre 2023, par DejiEdit : I'm rewriting this entire question


Goal : To reconstruct a video from its pieces/chunks from a network stream inside of an
@ffmpeg/ffmpeg
worker

Problems :


- 

- Video chunks/pieces which come after the first piece/chunk are reported by
@ffmpeg/ffmpeg
to have invalid data, as seen in the log below :




{
 "type": "stderr",
 "message": "video-0_chunk-1.part: Invalid data found when processing input"
}



- 

- How would I merge these chunks/pieces to reconstruct the full video using
@ffmpeg/ffmpeg
(after solving the first issue above)




My current code situation :


- 

- For merging the video pieces




const constructFile = async (chunks: Uint8Array[], queueId: number) => {
 await Promise.all(
 chunks.map(async (chunk, index) => {
 const chunkFile = `video-${queueId}_chunk-${index}`;
 await ffmpeg.writeFile(chunkFile, chunk);

 // Return information about newly created file
 ffmpeg.exec(["-i", chunkFile]);
 })
 );
};



I'm reading the logs/output for


ffmpeg.exec(['-i', chunkFile])



using


ffmpeg.on('log', (log) => console.log(log))



- 

- For fetching the videos using streams




await useFetch(Capacitor.convertFileSrc(file.path), {
 responseType: "stream",

 onResponse: async ({ response }) => {
 if (response.body) {
 const reader = response.body.getReader();

 while (true) {
 const { done, value } = await reader.read();

 if (done) break;
 file.chunks.push(value);
 }
 reader.releaseLock();
 }
 },
});



Note : file.chunks is linked to a reactive value which is passed to
constructFile()
when initialized

These are the logs I get from the code currently above :


chunk-4OF65L5M.js:2710 <suspense> is an experimental feature and its API will likely change.
(index):298 native App.addListener (#25407936)
(index):298 native FilePicker.pickVideos (#25407937)
(index):272 result FilePicker.pickVideos (#25407937)
(index):298 native VideoEditor.thumbnail (#25407938)
(index):272 result VideoEditor.thumbnail (#25407938)
Processing.vue:135 {type: 'stderr', message: 'ffmpeg version 5.1.3 Copyright (c) 2000-2022 the FFmpeg developers'}
Processing.vue:135 {type: 'stderr', message: ' built with emcc (Emscripten gcc/clang-like repla…3.1.40 (5c27e79dd0a9c4e27ef2326841698cdd4f6b5784)'}
Processing.vue:135 {type: 'stderr', message: ' configuration: --target-os=none --arch=x86_32 --…e-libfreetype --enable-libfribidi --enable-libass'}
Processing.vue:135 {type: 'stderr', message: ' libavutil 57. 28.100 / 57. 28.100'}
Processing.vue:135 {type: 'stderr', message: ' libavcodec 59. 37.100 / 59. 37.100'}
Processing.vue:135 {type: 'stderr', message: ' libavformat 59. 27.100 / 59. 27.100'}
Processing.vue:135 {type: 'stderr', message: ' libavdevice 59. 7.100 / 59. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libavfilter 8. 44.100 / 8. 44.100'}
Processing.vue:135 {type: 'stderr', message: ' libswscale 6. 7.100 / 6. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libswresample 4. 7.100 / 4. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libpostproc 56. 6.100 / 56. 6.100'}
Processing.vue:135 {type: 'stderr', message: "Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'video-0_chunk-0':"}
Processing.vue:135 {type: 'stderr', message: ' Metadata:'}
Processing.vue:135 {type: 'stderr', message: ' major_brand : mp42'}
Processing.vue:135 {type: 'stderr', message: ' minor_version : 0'}
Processing.vue:135 {type: 'stderr', message: ' compatible_brands: isommp42'}
Processing.vue:135 {type: 'stderr', message: ' creation_time : 2022-11-29T14:46:32.000000Z'}
Processing.vue:135 {type: 'stderr', message: ' Duration: 00:00:51.50, start: 0.000000, bitrate: 81 kb/s'}
Processing.vue:135 {type: 'stderr', message: ' Stream #0:0[0x1](und): Video: h264 (High) (avc1 …6], 259 kb/s, 30 fps, 30 tbr, 15360 tbn (default)'}
Processing.vue:135 {type: 'stderr', message: ' Metadata:'}
Processing.vue:135 {type: 'stderr', message: ' creation_time : 2022-11-29T14:46:32.000000Z'}
Processing.vue:135 {type: 'stderr', message: ' handler_name : ISO Media file produced by Google Inc. Created on: 11/29/2022.'}
Processing.vue:135 {type: 'stderr', message: ' vendor_id : [0][0][0][0]'}
Processing.vue:135 {type: 'stderr', message: ' Stream #0:1[0x2](und): Audio: aac (LC) (mp4a / 0…706D), 44100 Hz, stereo, fltp, 127 kb/s (default)'}
Processing.vue:135 {type: 'stderr', message: ' Metadata:'}
Processing.vue:135 {type: 'stderr', message: ' creation_time : 2022-11-29T14:46:32.000000Z'}
Processing.vue:135 {type: 'stderr', message: ' handler_name : ISO Media file produced by Google Inc. Created on: 11/29/2022.'}
Processing.vue:135 {type: 'stderr', message: ' vendor_id : [0][0][0][0]'}
Processing.vue:135 {type: 'stderr', message: 'At least one output file must be specified'}
Processing.vue:135 {type: 'stderr', message: 'Aborted()'}
Processing.vue:135 {type: 'stderr', message: 'ffmpeg version 5.1.3 Copyright (c) 2000-2022 the FFmpeg developers'}
Processing.vue:135 {type: 'stderr', message: ' built with emcc (Emscripten gcc/clang-like repla…3.1.40 (5c27e79dd0a9c4e27ef2326841698cdd4f6b5784)'}
Processing.vue:135 {type: 'stderr', message: ' configuration: --target-os=none --arch=x86_32 --…e-libfreetype --enable-libfribidi --enable-libass'}
Processing.vue:135 {type: 'stderr', message: ' libavutil 57. 28.100 / 57. 28.100'}
Processing.vue:135 {type: 'stderr', message: ' libavcodec 59. 37.100 / 59. 37.100'}
Processing.vue:135 {type: 'stderr', message: ' libavformat 59. 27.100 / 59. 27.100'}
Processing.vue:135 {type: 'stderr', message: ' libavdevice 59. 7.100 / 59. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libavfilter 8. 44.100 / 8. 44.100'}
Processing.vue:135 {type: 'stderr', message: ' libswscale 6. 7.100 / 6. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libswresample 4. 7.100 / 4. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libpostproc 56. 6.100 / 56. 6.100'}
Processing.vue:135 {type: 'stderr', message: 'video-0_chunk-1: Invalid data found when processing input'}
Processing.vue:135 {type: 'stderr', message: 'Aborted()'}
Processing.vue:135 {type: 'stderr', message: 'ffmpeg version 5.1.3 Copyright (c) 2000-2022 the FFmpeg developers'}
Processing.vue:135 {type: 'stderr', message: ' built with emcc (Emscripten gcc/clang-like repla…3.1.40 (5c27e79dd0a9c4e27ef2326841698cdd4f6b5784)'}
Processing.vue:135 {type: 'stderr', message: ' configuration: --target-os=none --arch=x86_32 --…e-libfreetype --enable-libfribidi --enable-libass'}
Processing.vue:135 {type: 'stderr', message: ' libavutil 57. 28.100 / 57. 28.100'}
Processing.vue:135 {type: 'stderr', message: ' libavcodec 59. 37.100 / 59. 37.100'}
Processing.vue:135 {type: 'stderr', message: ' libavformat 59. 27.100 / 59. 27.100'}
Processing.vue:135 {type: 'stderr', message: ' libavdevice 59. 7.100 / 59. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libavfilter 8. 44.100 / 8. 44.100'}
Processing.vue:135 {type: 'stderr', message: ' libswscale 6. 7.100 / 6. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libswresample 4. 7.100 / 4. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libpostproc 56. 6.100 / 56. 6.100'}
Processing.vue:135 {type: 'stderr', message: 'video-0_chunk-2: Invalid data found when processing input'}
Processing.vue:135 {type: 'stderr', message: 'Aborted()'}
Processing.vue:135 {type: 'stderr', message: 'ffmpeg version 5.1.3 Copyright (c) 2000-2022 the FFmpeg developers'}
Processing.vue:135 {type: 'stderr', message: ' built with emcc (Emscripten gcc/clang-like repla…3.1.40 (5c27e79dd0a9c4e27ef2326841698cdd4f6b5784)'}
Processing.vue:135 {type: 'stderr', message: ' configuration: --target-os=none --arch=x86_32 --…e-libfreetype --enable-libfribidi --enable-libass'}
Processing.vue:135 {type: 'stderr', message: ' libavutil 57. 28.100 / 57. 28.100'}
Processing.vue:135 {type: 'stderr', message: ' libavcodec 59. 37.100 / 59. 37.100'}
Processing.vue:135 {type: 'stderr', message: ' libavformat 59. 27.100 / 59. 27.100'}
Processing.vue:135 {type: 'stderr', message: ' libavdevice 59. 7.100 / 59. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libavfilter 8. 44.100 / 8. 44.100'}
Processing.vue:135 {type: 'stderr', message: ' libswscale 6. 7.100 / 6. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libswresample 4. 7.100 / 4. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libpostproc 56. 6.100 / 56. 6.100'}
Processing.vue:135 {type: 'stderr', message: 'video-0_chunk-3: Invalid data found when processing input'}
Processing.vue:135 {type: 'stderr', message: 'Aborted()'}
Processing.vue:135 {type: 'stderr', message: 'ffmpeg version 5.1.3 Copyright (c) 2000-2022 the FFmpeg developers'}
Processing.vue:135 {type: 'stderr', message: ' built with emcc (Emscripten gcc/clang-like repla…3.1.40 (5c27e79dd0a9c4e27ef2326841698cdd4f6b5784)'}
Processing.vue:135 {type: 'stderr', message: ' configuration: --target-os=none --arch=x86_32 --…e-libfreetype --enable-libfribidi --enable-libass'}
Processing.vue:135 {type: 'stderr', message: ' libavutil 57. 28.100 / 57. 28.100'}
Processing.vue:135 {type: 'stderr', message: ' libavcodec 59. 37.100 / 59. 37.100'}
Processing.vue:135 {type: 'stderr', message: ' libavformat 59. 27.100 / 59. 27.100'}
Processing.vue:135 {type: 'stderr', message: ' libavdevice 59. 7.100 / 59. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libavfilter 8. 44.100 / 8. 44.100'}
Processing.vue:135 {type: 'stderr', message: ' libswscale 6. 7.100 / 6. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libswresample 4. 7.100 / 4. 7.100'}
Processing.vue:135 {type: 'stderr', message: ' libpostproc 56. 6.100 / 56. 6.100'}
Processing.vue:135 {type: 'stderr', message: 'video-0_chunk-4: Invalid data found when processing input'}
Processing.vue:135 {type: 'stderr', message: 'Aborted()'}
</suspense>


Notes :


- 

- The sections which start with
Processing.vue
come from the logging system I've setup. - The pieces/chunks gotten from the network where stored in exactly the same order in which they came
- If you've seen the old question, the
ReferenceError
happens as a result of HMR by Vite
- 

- Similar to this, some logs were repeated twice because I was actively changing some things and the component had to rerun from the start












Summary : If my problem is still not clear, you could provide another way of fetching a large file (video) from a network, loading the file into memory and passing the file data to
@ffmpeg/ffmpeg
for further processing

- Video chunks/pieces which come after the first piece/chunk are reported by
-
ffmpeg - allow to create empty aac file
27 juillet 2023, par user11149927I have two commands :


ffmpeg -y -i file.mp4 -vn -acodec copy file.aac



and then :


ffmpeg -y -i file.mp4 -i file.aac -c:v copy -c:a aac new-file.mp4



The first command throw error when the video has no audio :


Output file does not contain any stream



I would like to change first command to allow create empty aac file (maybe silent audio) when video has no audio. Or maybe exists better solution ?