Process a new layer of video or audio
| 638 | |
| 639 | // Process a new layer of video or audio |
| 640 | void Timeline::add_layer(std::shared_ptr<Frame> new_frame, Clip* source_clip, int64_t clip_frame_number, bool is_top_clip, float max_volume) |
| 641 | { |
| 642 | // Create timeline options (with details about this current frame request) |
| 643 | TimelineInfoStruct options{}; |
| 644 | options.is_top_clip = is_top_clip; |
| 645 | options.is_before_clip_keyframes = true; |
| 646 | |
| 647 | // Get the clip's frame, composited on top of the current timeline frame |
| 648 | std::shared_ptr<Frame> source_frame; |
| 649 | source_frame = GetOrCreateFrame(new_frame, source_clip, clip_frame_number, &options); |
| 650 | |
| 651 | // No frame found... so bail |
| 652 | if (!source_frame) |
| 653 | return; |
| 654 | |
| 655 | // Debug output |
| 656 | ZmqLogger::Instance()->AppendDebugMethod( |
| 657 | "Timeline::add_layer", |
| 658 | "new_frame->number", new_frame->number, |
| 659 | "clip_frame_number", clip_frame_number); |
| 660 | |
| 661 | /* COPY AUDIO - with correct volume */ |
| 662 | if (source_clip->Reader()->info.has_audio) { |
| 663 | // Debug output |
| 664 | ZmqLogger::Instance()->AppendDebugMethod( |
| 665 | "Timeline::add_layer (Copy Audio)", |
| 666 | "source_clip->Reader()->info.has_audio", source_clip->Reader()->info.has_audio, |
| 667 | "source_frame->GetAudioChannelsCount()", source_frame->GetAudioChannelsCount(), |
| 668 | "info.channels", info.channels, |
| 669 | "clip_frame_number", clip_frame_number); |
| 670 | |
| 671 | if (source_frame->GetAudioChannelsCount() == info.channels && source_clip->has_audio.GetInt(clip_frame_number) != 0) |
| 672 | { |
| 673 | // Ensure timeline frame matches the source samples once per frame |
| 674 | if (new_frame->GetAudioSamplesCount() != source_frame->GetAudioSamplesCount()){ |
| 675 | new_frame->ResizeAudio(info.channels, source_frame->GetAudioSamplesCount(), info.sample_rate, info.channel_layout); |
| 676 | } |
| 677 | |
| 678 | // Apply transition-driven equal-power audio fades for clips covered by a Mask transition. |
| 679 | const auto transition_audio_gains = ResolveTransitionAudioGains(source_clip, new_frame->number, is_top_clip); |
| 680 | |
| 681 | for (int channel = 0; channel < source_frame->GetAudioChannelsCount(); channel++) |
| 682 | { |
| 683 | // Get volume from previous frame and this frame |
| 684 | float previous_volume = source_clip->volume.GetValue(clip_frame_number - 1); |
| 685 | float volume = source_clip->volume.GetValue(clip_frame_number); |
| 686 | previous_volume *= transition_audio_gains.first; |
| 687 | volume *= transition_audio_gains.second; |
| 688 | int channel_filter = source_clip->channel_filter.GetInt(clip_frame_number); // optional channel to filter (if not -1) |
| 689 | int channel_mapping = source_clip->channel_mapping.GetInt(clip_frame_number); // optional channel to map this channel to (if not -1) |
| 690 | |
| 691 | // Apply volume mixing strategy |
| 692 | if (source_clip->mixing == VOLUME_MIX_AVERAGE && max_volume > 1.0) { |
| 693 | // Don't allow this clip to exceed 100% (divide volume equally between all overlapping clips with volume |
| 694 | previous_volume = previous_volume / max_volume; |
| 695 | volume = volume / max_volume; |
| 696 | } |
| 697 | else if (source_clip->mixing == VOLUME_MIX_REDUCE && max_volume > 1.0) { |
nothing calls this directly
no test coverage detected