MayaFlux 0.1.0
Digital-First Multimedia Processing Framework
Loading...
Searching...
No Matches

◆ decode_frames()

std::vector< Kakshya::DataVariant > MayaFlux::IO::SoundFileReader::decode_frames ( std::shared_ptr< FFmpegContext ctx,
uint64_t  num_frames,
uint64_t  offset 
)
private

Decode a specific number of frames from the file.

Parameters
ctxFFmpeg context.
num_framesNumber of frames to decode.
offsetFrame offset from beginning.
Returns
DataVariant containing decoded data.

Definition at line 554 of file SoundFileReader.cpp.

558{
559 if (!ctx || !ctx->is_valid() || !ctx->swr_context) {
560 set_error("Invalid context for decoding");
561 return {};
562 }
563
564 std::vector<Kakshya::DataVariant> output_data;
565 uint64_t frames_decoded = 0;
566
567 AVPacket* packet = av_packet_alloc();
568 AVFrame* frame = av_frame_alloc();
569
570 if (!packet || !frame) {
571 av_packet_free(&packet);
572 av_frame_free(&frame);
573 set_error("Failed to allocate packet/frame");
574 return {};
575 }
576
577 int channels = ctx->channels;
579
580 if (use_planar) {
581 output_data.resize(channels);
582 for (auto& channel_vector : output_data) {
583 channel_vector = std::vector<double>();
584 std::get<std::vector<double>>(channel_vector).reserve(num_frames);
585 }
586 } else {
587 output_data.resize(1);
588 output_data[0] = std::vector<double>();
589 std::get<std::vector<double>>(output_data[0]).reserve(num_frames * channels);
590 }
591
592 uint8_t** resample_buffer = nullptr;
593 int resample_linesize = 0;
594
595 int max_resample_samples = av_rescale_rnd(
596 num_frames,
597 m_target_sample_rate > 0 ? m_target_sample_rate : ctx->sample_rate,
598 ctx->sample_rate,
599 AV_ROUND_UP);
600
601 AVSampleFormat target_format = use_planar ? AV_SAMPLE_FMT_DBLP : AV_SAMPLE_FMT_DBL;
602
603 int alloc_ret = av_samples_alloc_array_and_samples(
604 &resample_buffer, &resample_linesize,
605 channels, max_resample_samples, target_format, 0);
606
607 if (alloc_ret < 0 || !resample_buffer) {
608 av_packet_free(&packet);
609 av_frame_free(&frame);
610 set_error("Failed to allocate resample buffer");
611 return {};
612 }
613
614 while (frames_decoded < num_frames) {
615 int ret = av_read_frame(ctx->format_context, packet);
616
617 if (ret < 0) {
618 if (ret == AVERROR_EOF) {
619 avcodec_send_packet(ctx->codec_context, nullptr);
620 } else {
621 break;
622 }
623 } else if (packet->stream_index != ctx->audio_stream_index) {
624 av_packet_unref(packet);
625 continue;
626 } else {
627 ret = avcodec_send_packet(ctx->codec_context, packet);
628 av_packet_unref(packet);
629
630 if (ret < 0 && ret != AVERROR(EAGAIN)) {
631 continue;
632 }
633 }
634
635 while (ret >= 0 && frames_decoded < num_frames) {
636 ret = avcodec_receive_frame(ctx->codec_context, frame);
637
638 if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
639 break;
640 } else if (ret < 0) {
641 break;
642 }
643
644 int out_samples = swr_convert(ctx->swr_context,
645 resample_buffer, max_resample_samples,
646 (const uint8_t**)frame->data, frame->nb_samples);
647
648 if (out_samples > 0) {
649 uint64_t samples_to_copy = std::min(
650 static_cast<uint64_t>(out_samples),
651 num_frames - frames_decoded);
652
653 if (use_planar) {
654 for (int ch = 0; ch < channels; ++ch) {
655 double* channel_data = reinterpret_cast<double*>(resample_buffer[ch]);
656 auto& channel_vector = std::get<std::vector<double>>(output_data[ch]);
657 channel_vector.insert(channel_vector.end(),
658 channel_data, channel_data + samples_to_copy);
659 }
660 } else {
661 double* interleaved_data = reinterpret_cast<double*>(resample_buffer[0]);
662 auto& interleaved_vector = std::get<std::vector<double>>(output_data[0]);
663 interleaved_vector.insert(interleaved_vector.end(),
664 interleaved_data, interleaved_data + samples_to_copy * channels);
665 }
666
667 frames_decoded += samples_to_copy;
668 }
669
670 av_frame_unref(frame);
671 }
672
673 if (ret == AVERROR_EOF) {
674 break;
675 }
676 }
677
678 av_frame_free(&frame);
679 av_packet_free(&packet);
680
681 if (resample_buffer) {
682 av_freep(&resample_buffer[0]);
683 av_freep(&resample_buffer);
684 }
685
686 m_current_frame_position = offset + frames_decoded;
687 return output_data;
688}
uint32_t m_target_sample_rate
Target sample rate for resampling (0 = use source rate).
void set_error(const std::string &error) const
Set the last error message.
std::atomic< uint64_t > m_current_frame_position
Current frame position for reading.
AudioReadOptions m_audio_options
Audio-specific read options.

References MayaFlux::IO::DEINTERLEAVE, m_audio_options, m_current_frame_position, m_target_sample_rate, MayaFlux::IO::NONE, and set_error().

Referenced by read_frames().

+ Here is the call graph for this function:
+ Here is the caller graph for this function: