548 const std::string source =
549 isUrl(requested_path)
551 : std::filesystem::absolute(requested_path)
554 if (!isUrl(source) &&
555 !std::filesystem::is_regular_file(std::filesystem::path(source))) {
556 std::cerr <<
"acmxvk: audio file is not readable: " << source
560 const std::size_t initial_sample_count =
samples.size();
562 AVFormatContext *format =
nullptr;
563 AVCodecContext *codec =
nullptr;
564 SwrContext *resampler =
nullptr;
565 AVPacket *packet =
nullptr;
566 AVFrame *frame =
nullptr;
568 auto release = [&]() {
569 av_frame_free(&frame);
570 av_packet_free(&packet);
571 swr_free(&resampler);
572 avcodec_free_context(&codec);
573 avformat_close_input(&format);
576 int result = avformat_open_input(&format, source.c_str(),
nullptr,
nullptr);
578 std::cerr <<
"acmxvk: could not open audio file: "
579 << ffmpegError(result) <<
'\n';
583 result = avformat_find_stream_info(format,
nullptr);
585 std::cerr <<
"acmxvk: could not read audio stream information: "
586 << ffmpegError(result) <<
'\n';
591 const AVCodec *decoder =
nullptr;
592 const int stream_index = av_find_best_stream(
593 format, AVMEDIA_TYPE_AUDIO, -1, -1, &decoder, 0);
594 if (stream_index < 0 || decoder ==
nullptr) {
595 std::cerr <<
"acmxvk: media file contains no decodable audio stream\n";
600 codec = avcodec_alloc_context3(decoder);
601 if (codec ==
nullptr) {
602 std::cerr <<
"acmxvk: could not allocate the audio decoder\n";
606 result = avcodec_parameters_to_context(
607 codec, format->streams[stream_index]->codecpar);
608 if (result < 0 || (result = avcodec_open2(codec, decoder,
nullptr)) < 0) {
609 std::cerr <<
"acmxvk: could not initialize the audio decoder: "
610 << ffmpegError(result) <<
'\n';
614 if (codec->sample_rate <= 0 || codec->ch_layout.nb_channels == 0) {
615 std::cerr <<
"acmxvk: audio stream has an invalid sample format\n";
620 AVChannelLayout output_layout = AV_CHANNEL_LAYOUT_MONO;
621 result = swr_alloc_set_opts2(
622 &resampler, &output_layout, AV_SAMPLE_FMT_FLT,
623 static_cast<int>(FILE_SAMPLE_RATE), &codec->ch_layout,
624 codec->sample_fmt, codec->sample_rate, 0,
nullptr);
625 av_channel_layout_uninit(&output_layout);
626 if (result < 0 || resampler ==
nullptr ||
627 (result = swr_init(resampler)) < 0) {
628 std::cerr <<
"acmxvk: could not initialize audio resampling: "
629 << ffmpegError(result) <<
'\n';
634 packet = av_packet_alloc();
635 frame = av_frame_alloc();
636 if (packet ==
nullptr || frame ==
nullptr) {
637 std::cerr <<
"acmxvk: could not allocate FFmpeg audio frames\n";
642 auto append_frame = [&]() ->
bool {
643 const int capacity =
static_cast<int>(av_rescale_rnd(
644 swr_get_delay(resampler, codec->sample_rate) + frame->nb_samples,
645 FILE_SAMPLE_RATE, codec->sample_rate, AV_ROUND_UP));
649 std::vector<float> converted(
static_cast<std::size_t
>(capacity));
650 std::uint8_t *
output[] = {
651 reinterpret_cast<std::uint8_t *
>(converted.data())};
652 const int count = swr_convert(
653 resampler,
output, capacity,
654 const_cast<const std::uint8_t **
>(frame->extended_data),
657 std::cerr <<
"acmxvk: audio resampling failed: "
658 << ffmpegError(count) <<
'\n';
662 converted.begin() + count);
666 auto drain_decoder = [&]() ->
bool {
668 const int receive = avcodec_receive_frame(codec, frame);
669 if (receive == AVERROR(EAGAIN) || receive == AVERROR_EOF) {
673 std::cerr <<
"acmxvk: audio decoding failed: "
674 << ffmpegError(receive) <<
'\n';
677 if (!append_frame()) {
680 av_frame_unref(frame);
685 while ((result = av_read_frame(format, packet)) >= 0) {
686 if (packet->stream_index == stream_index) {
687 result = avcodec_send_packet(codec, packet);
688 if (result < 0 || !drain_decoder()) {
690 std::cerr <<
"acmxvk: could not submit audio packet: "
691 << ffmpegError(result) <<
'\n';
696 av_packet_unref(packet);
702 result = avcodec_send_packet(codec,
nullptr);
703 decoded = (result >= 0 || result == AVERROR_EOF) && drain_decoder();
707 const int capacity =
static_cast<int>(av_rescale_rnd(
708 swr_get_delay(resampler, codec->sample_rate), FILE_SAMPLE_RATE,
709 codec->sample_rate, AV_ROUND_UP));
713 std::vector<float> converted(
static_cast<std::size_t
>(capacity));
714 std::uint8_t *
output[] = {
715 reinterpret_cast<std::uint8_t *
>(converted.data())};
717 swr_convert(resampler,
output, capacity,
nullptr, 0);
719 decoded = count == 0;
723 converted.begin() + count);
727 const std::size_t decoded_sample_count =
728 samples.size() - initial_sample_count;
729 if (!decoded || decoded_sample_count == 0) {
730 samples.resize(initial_sample_count);
731 std::cerr <<
"acmxvk: audio file produced no usable samples: "
736 std::cout <<
"acmxvk: decoded audio track " << source <<
" ("
737 <<
static_cast<double>(decoded_sample_count) /
738 static_cast<double>(FILE_SAMPLE_RATE)
739 <<
" seconds, " << decoded_sample_count
740 <<
" mono samples at " << FILE_SAMPLE_RATE <<
" Hz)\n";
799 double video_duration) {
801 if (
samples.empty() || !std::isfinite(video_duration) ||
802 video_duration <= 0.0) {
803 std::cerr <<
"acmxvk: cannot mux "
806 <<
" without samples and a positive video duration\n";
810 const std::filesystem::path video_path =
811 std::filesystem::absolute(requested_video_path).lexically_normal();
812 if (!std::filesystem::is_regular_file(video_path)) {
813 std::cerr <<
"acmxvk: encoded video is not readable for audio mux: "
814 << video_path.string() <<
'\n';
819 const double mux_duration =
820 repeat ? video_duration : std::min(video_duration, source_duration);
821 const std::int64_t target_sample_count =
822 static_cast<std::int64_t
>(std::floor(
823 mux_duration *
static_cast<double>(FILE_SAMPLE_RATE)));
824 if (target_sample_count <= 0) {
825 std::cerr <<
"acmxvk: file audio mux duration is empty\n";
829 const auto unique_value = std::chrono::steady_clock::now()
832 const std::filesystem::path temporary_path =
833 video_path.parent_path() /
834 (video_path.stem().
string() +
".acmxvk-mux-" +
835 std::to_string(unique_value) + video_path.extension().string());
836 const std::string video_url = ffmpegPath(video_path);
837 const std::string temporary_url = ffmpegPath(temporary_path);
839 AVFormatContext *input_context =
nullptr;
840 AVFormatContext *output_context =
nullptr;
841 AVCodecContext *audio_encoder =
nullptr;
842 SwrContext *resampler =
nullptr;
843 AVFrame *audio_frame =
nullptr;
844 AVPacket *input_packet =
nullptr;
845 AVPacket *audio_packet =
nullptr;
847 auto cleanup = [&]() {
848 av_packet_free(&audio_packet);
849 av_packet_free(&input_packet);
850 av_frame_free(&audio_frame);
851 swr_free(&resampler);
852 avcodec_free_context(&audio_encoder);
853 avformat_close_input(&input_context);
854 if (output_context !=
nullptr) {
855 if ((output_context->oformat->flags & AVFMT_NOFILE) == 0) {
856 avio_closep(&output_context->pb);
858 avformat_free_context(output_context);
859 output_context =
nullptr;
863 auto fail = [&](std::string_view message,
int error) {
864 std::cerr <<
"acmxvk: " << message;
866 std::cerr <<
": " << ffmpegError(error);
870 std::error_code remove_error;
871 std::filesystem::remove(temporary_path, remove_error);
875 int result = avformat_open_input(&input_context, video_url.c_str(),
878 return fail(
"could not open encoded video for audio mux", result);
880 result = avformat_find_stream_info(input_context,
nullptr);
882 return fail(
"could not read encoded video stream information",
885 const int input_video_index = av_find_best_stream(
886 input_context, AVMEDIA_TYPE_VIDEO, -1, -1,
nullptr, 0);
887 if (input_video_index < 0) {
888 return fail(
"encoded output contains no video stream",
892 result = avformat_alloc_output_context2(
893 &output_context,
nullptr,
nullptr, temporary_url.c_str());
894 if (result < 0 || output_context ==
nullptr) {
895 return fail(
"could not create audio-mux output container", result);
898 AVStream *input_video = input_context->streams[input_video_index];
899 AVStream *output_video = avformat_new_stream(output_context,
nullptr);
900 if (output_video ==
nullptr) {
901 return fail(
"could not create remuxed video stream", AVERROR(ENOMEM));
903 result = avcodec_parameters_copy(output_video->codecpar,
904 input_video->codecpar);
906 return fail(
"could not copy encoded video parameters", result);
908 output_video->codecpar->codec_tag = 0;
909 output_video->time_base = input_video->time_base;
910 output_video->avg_frame_rate = input_video->avg_frame_rate;
912 const AVCodec *aac_encoder = avcodec_find_encoder(AV_CODEC_ID_AAC);
913 if (aac_encoder ==
nullptr) {
914 return fail(
"linked FFmpeg has no AAC encoder", AVERROR_ENCODER_NOT_FOUND);
916 AVStream *output_audio =
917 avformat_new_stream(output_context, aac_encoder);
918 if (output_audio ==
nullptr) {
919 return fail(
"could not create encoded audio stream", AVERROR(ENOMEM));
921 audio_encoder = avcodec_alloc_context3(aac_encoder);
922 if (audio_encoder ==
nullptr) {
923 return fail(
"could not allocate AAC encoder", AVERROR(ENOMEM));
925 audio_encoder->bit_rate = 192000;
926 audio_encoder->sample_fmt = AV_SAMPLE_FMT_FLTP;
927 audio_encoder->sample_rate =
static_cast<int>(FILE_SAMPLE_RATE);
928 audio_encoder->time_base =
929 AVRational{1,
static_cast<int>(FILE_SAMPLE_RATE)};
930 av_channel_layout_default(&audio_encoder->ch_layout, 1);
931 if ((output_context->oformat->flags & AVFMT_GLOBALHEADER) != 0) {
932 audio_encoder->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
934 result = avcodec_open2(audio_encoder, aac_encoder,
nullptr);
936 return fail(
"could not initialize AAC encoder", result);
938 result = avcodec_parameters_from_context(output_audio->codecpar,
941 return fail(
"could not export AAC stream parameters", result);
943 output_audio->codecpar->codec_tag = 0;
944 output_audio->time_base = audio_encoder->time_base;
946 AVChannelLayout input_layout = AV_CHANNEL_LAYOUT_MONO;
947 result = swr_alloc_set_opts2(
948 &resampler, &audio_encoder->ch_layout, audio_encoder->sample_fmt,
949 audio_encoder->sample_rate, &input_layout, AV_SAMPLE_FMT_FLT,
950 static_cast<int>(FILE_SAMPLE_RATE), 0,
nullptr);
951 av_channel_layout_uninit(&input_layout);
952 if (result < 0 || resampler ==
nullptr ||
953 (result = swr_init(resampler)) < 0) {
954 return fail(
"could not initialize audio mux resampler", result);
957 const int audio_frame_capacity =
958 audio_encoder->frame_size > 0 ? audio_encoder->frame_size : 1024;
959 audio_frame = av_frame_alloc();
960 input_packet = av_packet_alloc();
961 audio_packet = av_packet_alloc();
962 if (audio_frame ==
nullptr || input_packet ==
nullptr ||
963 audio_packet ==
nullptr) {
964 return fail(
"could not allocate audio mux frames", AVERROR(ENOMEM));
966 audio_frame->format = audio_encoder->sample_fmt;
967 audio_frame->sample_rate = audio_encoder->sample_rate;
968 audio_frame->nb_samples = audio_frame_capacity;
969 result = av_channel_layout_copy(&audio_frame->ch_layout,
970 &audio_encoder->ch_layout);
971 if (result < 0 || (result = av_frame_get_buffer(audio_frame, 0)) < 0) {
972 return fail(
"could not allocate AAC sample buffer", result);
975 if ((output_context->oformat->flags & AVFMT_NOFILE) == 0) {
976 result = avio_open(&output_context->pb, temporary_url.c_str(),
979 return fail(
"could not open temporary mux output", result);
982 result = avformat_write_header(output_context,
nullptr);
984 return fail(
"could not write audio-mux container header", result);
987 std::int64_t source_position = 0;
988 std::int64_t encoded_position = 0;
989 std::vector<float> input_samples(
990 static_cast<std::size_t
>(audio_frame_capacity));
992 auto drain_audio_packets = [&]() {
995 avcodec_receive_packet(audio_encoder, audio_packet);
996 if (receive == AVERROR(EAGAIN) || receive == AVERROR_EOF) {
1003 audio_packet->stream_index = output_audio->index;
1004 av_packet_rescale_ts(audio_packet, audio_encoder->time_base,
1005 output_audio->time_base);
1007 av_interleaved_write_frame(output_context, audio_packet);
1008 av_packet_unref(audio_packet);
1016 auto encode_audio_frame = [&]() {
1017 const std::int64_t remaining =
1018 target_sample_count - source_position;
1019 if (remaining <= 0) {
1022 const int source_count =
static_cast<int>(
1023 std::min<std::int64_t>(remaining, audio_frame_capacity));
1024 int submitted_count = source_count;
1025 if (source_count < audio_frame_capacity &&
1026 (aac_encoder->capabilities &
1027 AV_CODEC_CAP_SMALL_LAST_FRAME) == 0) {
1028 submitted_count = audio_frame_capacity;
1030 for (
int index = 0; index < submitted_count; ++index) {
1031 if (index >= source_count) {
1032 input_samples[
static_cast<std::size_t
>(index)] = 0.0F;
1035 const std::size_t sample_index =
repeat
1036 ?
static_cast<std::size_t
>(source_position + index) %
1038 :
static_cast<std::size_t
>(source_position + index);
1039 input_samples[
static_cast<std::size_t
>(index)] =
1043 audio_frame->nb_samples = submitted_count;
1044 result = av_frame_make_writable(audio_frame);
1048 const std::uint8_t *input_data[] = {
1049 reinterpret_cast<const std::uint8_t *
>(input_samples.data())};
1050 const int converted = swr_convert(
1051 resampler, audio_frame->data, submitted_count, input_data,
1053 if (converted < 0) {
1057 audio_frame->nb_samples = converted;
1058 audio_frame->pts = encoded_position;
1059 result = avcodec_send_frame(audio_encoder, audio_frame);
1060 if (result < 0 || !drain_audio_packets()) {
1063 source_position += source_count;
1064 encoded_position += converted;
1068 bool video_complete =
false;
1069 while ((result = av_read_frame(input_context, input_packet)) >= 0) {
1070 if (input_packet->stream_index != input_video_index) {
1071 av_packet_unref(input_packet);
1074 const std::int64_t timestamp =
1075 input_packet->pts != AV_NOPTS_VALUE ? input_packet->pts
1076 : input_packet->dts;
1077 const double packet_time =
1078 timestamp == AV_NOPTS_VALUE
1080 :
static_cast<double>(timestamp) *
1081 av_q2d(input_video->time_base);
1082 if (timestamp != AV_NOPTS_VALUE && packet_time > mux_duration) {
1083 av_packet_unref(input_packet);
1084 video_complete =
true;
1088 const std::int64_t audio_target = std::min<std::int64_t>(
1089 target_sample_count,
1090 static_cast<std::int64_t
>(std::ceil(
1092 static_cast<double>(audio_frame_capacity) /
1093 static_cast<double>(FILE_SAMPLE_RATE)) *
1094 static_cast<double>(FILE_SAMPLE_RATE))));
1095 while (source_position < audio_target) {
1096 if (!encode_audio_frame()) {
1097 return fail(
"could not encode AAC samples", result);
1101 av_packet_rescale_ts(input_packet, input_video->time_base,
1102 output_video->time_base);
1103 input_packet->stream_index = output_video->index;
1104 input_packet->pos = -1;
1105 result = av_interleaved_write_frame(output_context, input_packet);
1106 av_packet_unref(input_packet);
1108 return fail(
"could not remux encoded video packet", result);
1111 if (!video_complete && result != AVERROR_EOF) {
1112 return fail(
"could not finish reading encoded video", result);
1115 while (source_position < target_sample_count) {
1116 if (!encode_audio_frame()) {
1117 return fail(
"could not finish AAC encoding", result);
1120 result = avcodec_send_frame(audio_encoder,
nullptr);
1121 if (result < 0 || !drain_audio_packets()) {
1122 return fail(
"could not flush AAC encoder", result);
1124 result = av_write_trailer(output_context);
1126 return fail(
"could not finalize audio-mux container", result);
1128 if ((output_context->oformat->flags & AVFMT_NOFILE) == 0) {
1129 result = avio_closep(&output_context->pb);
1131 return fail(
"could not flush temporary mux output", result);
1136 std::error_code replace_error;
1137 if (!replaceFile(temporary_path, video_path, replace_error)) {
1138 std::cerr <<
"acmxvk: could not atomically replace encoded video "
1139 "with muxed output: "
1140 << replace_error.message() <<
'\n';
1141 std::error_code remove_error;
1142 std::filesystem::remove(temporary_path, remove_error);
1146 std::cout <<
"acmxvk: muxed "
1148 ?
"live audio input"
1151 <<
" into " << video_path.string() <<
" (" << mux_duration
1152 <<
" seconds" << (
repeat ?
", repeated" :
"") <<
")\n";