Copy audio from one video file to another.
240 {
243 std::cerr << "Unsupported output format. Supported formats: .mp4, .mkv, .avi, .mov\n";
244 return;
245 }
246
247 AVFormatContext *source_ctx = nullptr, *dest_ctx = nullptr, *output_ctx = nullptr;
248 int source_audio_idx = -1, dest_video_idx = -1, dest_audio_idx = -1;
249 std::string temp_output = std::string(destVideoFile) + ".tmp";
250
251 if (avformat_open_input(&source_ctx, sourceAudioFile.data(), nullptr, nullptr) != 0 ||
252 avformat_open_input(&dest_ctx, destVideoFile.data(), nullptr, nullptr) != 0) {
253 std::cerr << "Failed to open input files\n";
255 return;
256 }
257
258 if (avformat_find_stream_info(source_ctx, nullptr) < 0 ||
259 avformat_find_stream_info(dest_ctx, nullptr) < 0) {
260 std::cerr << "Failed to find stream info\n";
262 return;
263 }
264
265 for (unsigned i = 0; i < source_ctx->nb_streams; ++i) {
266 if (source_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
267 source_audio_idx = i;
268 break;
269 }
270 }
271
272 for (unsigned i = 0; i < dest_ctx->nb_streams; ++i) {
273 AVMediaType type = dest_ctx->streams[i]->codecpar->codec_type;
274 if (type == AVMEDIA_TYPE_VIDEO)
275 dest_video_idx = i;
276 else if (type == AVMEDIA_TYPE_AUDIO)
277 dest_audio_idx = i;
278 }
279
280 if (source_audio_idx == -1 || dest_video_idx == -1) {
281 std::cerr << "Required streams not found\n";
283 return;
284 }
285
286 const AVOutputFormat *output_fmt = av_guess_format(nullptr, destVideoFile.data(), nullptr);
287 if (!output_fmt) {
288 output_fmt = av_guess_format("mp4", nullptr, nullptr);
289 if (!output_fmt) {
290 std::cerr << "Failed to determine output format\n";
292 return;
293 }
294 }
295
296 if (avformat_alloc_output_context2(&output_ctx, output_fmt, nullptr, temp_output.c_str()) < 0) {
297 std::cerr << "Failed to create output context\n";
299 return;
300 }
301
302 const AVCodec *audio_codec = avcodec_find_decoder(source_ctx->streams[source_audio_idx]->codecpar->codec_id);
303 if (!audio_codec) {
304 std::cerr << "Failed to find audio decoder\n";
306 return;
307 }
308
309 for (unsigned i = 0; i < dest_ctx->nb_streams; ++i) {
310 if (dest_ctx->streams[i]->codecpar->codec_type != AVMEDIA_TYPE_VIDEO) {
311 continue;
312 }
313
314 AVStream *dest_stream = dest_ctx->streams[i];
315 AVStream *out_stream = avformat_new_stream(output_ctx, nullptr);
316 if (!out_stream) {
317 std::cerr << "Failed to create output stream\n";
319 return;
320 }
321
322 if (avcodec_parameters_copy(out_stream->codecpar, dest_stream->codecpar) < 0) {
323 std::cerr << "Failed to copy video parameters\n";
325 return;
326 }
327
328 out_stream->time_base = dest_stream->time_base;
329 out_stream->codecpar->codec_tag = 0;
330 }
331
332 AVStream *out_stream = avformat_new_stream(output_ctx, audio_codec);
333 if (!out_stream) {
334 std::cerr << "Failed to create audio stream\n";
336 return;
337 }
338
339 AVCodecParameters *source_params = source_ctx->streams[source_audio_idx]->codecpar;
340 if (avcodec_parameters_copy(out_stream->codecpar, source_params) < 0) {
341 std::cerr << "Failed to copy audio parameters\n";
343 return;
344 }
345
346 if (source_params->frame_size == 0) {
347 out_stream->codecpar->frame_size = 1024;
348 } else {
349 out_stream->codecpar->frame_size = source_params->frame_size;
350 }
351
352 out_stream->time_base = source_ctx->streams[source_audio_idx]->time_base;
353 out_stream->codecpar->codec_tag = 0;
354 dest_audio_idx = out_stream->index;
355
356 if (!(output_ctx->oformat->flags & AVFMT_NOFILE)) {
357 if (avio_open(&output_ctx->pb, temp_output.c_str(), AVIO_FLAG_WRITE) < 0) {
358 std::cerr << "Failed to open output file\n";
360 return;
361 }
362 }
363 if (avformat_write_header(output_ctx, nullptr) < 0) {
364 std::cerr << "Failed to write header\n";
366 return;
367 }
368 AVPacket packet;
369 while (av_read_frame(dest_ctx, &packet) >= 0) {
370 if (packet.stream_index == dest_audio_idx) {
371 av_packet_unref(&packet);
372 continue;
373 }
374
375 AVStream *in_stream = dest_ctx->streams[packet.stream_index];
376 AVStream *out_stream = output_ctx->streams[packet.stream_index];
377 av_packet_rescale_ts(&packet, in_stream->time_base, out_stream->time_base);
378
379 if (av_interleaved_write_frame(output_ctx, &packet) < 0) {
380 std::cerr << "Failed to write packet\n";
381 av_packet_unref(&packet);
383 return;
384 }
385 av_packet_unref(&packet);
386 }
387
388 int64_t video_duration_ts = 0;
389 {
390 AVStream *vid_stream = dest_ctx->streams[0];
391 if (vid_stream->duration > 0) {
392 video_duration_ts = av_rescale_q(vid_stream->duration, vid_stream->time_base, source_ctx->streams[source_audio_idx]->time_base);
393 } else if (dest_ctx->duration > 0) {
394 AVRational av_tb = {1, AV_TIME_BASE};
395 video_duration_ts = av_rescale_q(dest_ctx->duration, av_tb, source_ctx->streams[source_audio_idx]->time_base);
396 }
397 }
398
399 av_seek_frame(source_ctx, source_audio_idx, 0, AVSEEK_FLAG_BACKWARD);
400 while (av_read_frame(source_ctx, &packet) >= 0) {
401 if (packet.stream_index == source_audio_idx) {
402 if (video_duration_ts > 0 && packet.pts != AV_NOPTS_VALUE && packet.pts > video_duration_ts) {
403 av_packet_unref(&packet);
404 break;
405 }
406 AVStream *in_stream = source_ctx->streams[packet.stream_index];
407 AVStream *out_stream = output_ctx->streams[dest_audio_idx];
408 av_packet_rescale_ts(&packet, in_stream->time_base, out_stream->time_base);
409 packet.stream_index = dest_audio_idx;
410
411 if (av_interleaved_write_frame(output_ctx, &packet) < 0) {
412 std::cerr << "Failed to write audio packet\n";
413 av_packet_unref(&packet);
415 return;
416 }
417 }
418 av_packet_unref(&packet);
419 }
420 av_write_trailer(output_ctx);
422 std::remove(destVideoFile.data());
423 std::rename(temp_output.c_str(), destVideoFile.data());
424}
std::mutex transfer_audio_mutex
bool is_format_supported(const char *filename)
void cleanup_contexts(AVFormatContext *source_ctx, AVFormatContext *dest_ctx, AVFormatContext *output_ctx)
Free FFmpeg format contexts used during transfer operations.