Menu

Copy op1a file

2017-07-25
2017-07-27
  • Sergey Romashev

    Sergey Romashev - 2017-07-25

    Hi respected.

    I try to write simple code which must copy op1a file without changes.
    It works when audio tracks have 1 channel. If audio tracks has 2 channels and more i get exception
    ERROR: 'size >= sample_size * num_samples' check failed
    ERROR: near OP1AContentPackage.cpp:702

    It happens in line "pcm_track->WriteSamples(channel...".

    May be you have simple code to understand principle to write op1a mxf files
    I tried to base on bmx\apps\bmxtranswrap\bmxtranswrap.cpp
    and bmx\apps\raw2bmx\raw2bmx.cpp

    Thank you in advance.

    My code:

    #include <stdio.h>
    #include <memory>
    #include "bmx/mxf_reader/MXFFileReader.h"
    #include "bmx/apps/AppMXFFileFactory.h"
    #include "bmx/clip_writer/ClipWriter.h"
    #include <bmx/essence_parser/SoundConversion.h>
    #include "OutputTrack.h"
    
    using namespace bmx;
    using namespace mxfpp;
    
    int main(int argc, char* argv[]) {
    
        if(argc < 2) {
            printf("No file specified.\n");
            return 1;
        }
    
        std::string fileName = argv[1];
        std::string outFileName = fileName + ".out";
        printf("FILE %s\n", fileName.c_str());
    
        AppMXFFileFactory file_factory;
        MXFFileReader file_reader = MXFFileReader();
        file_reader.SetFileFactory(&file_factory, false);
        file_reader.GetPackageResolver()->SetFileFactory(&file_factory, false);
        MXFFileReader::OpenResult result;
        result = file_reader.Open(fileName);
        int mxfVersion = file_reader.GetMXFVersion();
    
        if (result != MXFFileReader::MXF_RESULT_SUCCESS) {
            printf("Failed to open MXF file '%s': %s\n", fileName.c_str(), MXFFileReader::ResultToString(result).c_str());
            throw false;
        }
    
        MXFFileReader* reader = &file_reader;
    
        if (!reader->IsComplete()) {
            printf("Input file is incomplete\n");
        }
    
        Rational clip_frame_rate = reader->GetEditRate();
    
        // create output clip and initialize
        int16_t mxfFlavour = OP1A_MIN_PARTITIONS_FLAVOUR | OP1A_MP_TRACK_NUMBER_FLAVOUR;
        if(mxfVersion == MXF_PREFACE_VER(1, 2)){
            mxfFlavour |= OP1A_377_2004_FLAVOUR;
        }
        ClipWriter *clip = ClipWriter::OpenNewOP1AClip(mxfFlavour, file_factory.OpenNew(outFileName) , clip_frame_rate);
        OP1AFile *op1a_clip = clip->GetOP1AClip();
        op1a_clip->SetAddSystemItem(true);
    
        // create output tracks
        int audio_track_index = 0;
        std::shared_ptr<OutputTrack> output_video_track;
        std::shared_ptr<OutputTrack> output_anc_track;
        std::map<int, std::shared_ptr<OutputTrack>> output_audio_tracks;
    
        for (int i = 0; i < reader->GetNumTrackReaders(); i++) {
            MXFTrackReader *track_reader = reader->GetTrackReader(i);
            const MXFTrackInfo *input_track_info = track_reader->GetTrackInfo();
    
            printf("%i. %s\n", i, essence_type_to_string(input_track_info->essence_type));
    
            switch(input_track_info->essence_type) {
            case EssenceType::WAVE_PCM:
                {
                    auto outputTrack = std::make_shared < OutputTrack > (clip->CreateTrack(input_track_info->essence_type));
    
                    const MXFSoundTrackInfo *input_sound_info = dynamic_cast<const MXFSoundTrackInfo*>(reader->GetTrackReader(i)->GetTrackInfo());
                    OutputTrackSoundInfo *output_sound_info = outputTrack->GetSoundInfo();
                    output_sound_info->sampling_rate = input_sound_info->sampling_rate;
                    output_sound_info->bits_per_sample = input_sound_info->bits_per_sample;
                    output_sound_info->sequence_offset = 0;
                    outputTrack->SetPhysSrcTrackIndex(i+1);
                    ClipWriterTrack *clip_track = outputTrack->GetClipTrack();
                    clip_track->SetSamplingRate(output_sound_info->sampling_rate);
                    clip_track->SetQuantizationBits(output_sound_info->bits_per_sample);
                    clip_track->SetChannelCount(input_sound_info->channel_count);
                    clip_track->SetOutputTrackNumber(i+1);
    
                    printf("create output_audio_tracks[%d]\n", audio_track_index);
                    output_audio_tracks[audio_track_index] = outputTrack;
                    audio_track_index++;
                }
                break;
            case EssenceType::ANC_DATA:
                {
                    output_anc_track =  std::make_shared<OutputTrack>(clip->CreateTrack(input_track_info->essence_type));
                }
                break;
            case EssenceType::IEC_DV25:
                {
                    output_video_track = std::make_shared<OutputTrack>(clip->CreateTrack(input_track_info->essence_type));
                    ClipWriterTrack *clip_track = output_video_track->GetClipTrack();
                    clip_track->SetComponentDepth(8);
                }
                break;
            case EssenceType::DV100_1080I:
                {
                    output_video_track = std::make_shared<OutputTrack>(clip->CreateTrack(input_track_info->essence_type));
                    ClipWriterTrack *clip_track = output_video_track->GetClipTrack();
                    clip_track->SetComponentDepth(10);
                }
                break;
            default:
                printf("Unknown essence type %s\n", essence_type_to_string(input_track_info->essence_type));
                throw false;
            }
        }
    
        clip->PrepareHeaderMetadata();
        clip->PrepareWrite();
    
        // copy tracks
        uint32_t max_samples_per_read = 1;
        audio_track_index = 0;
        bmx::ByteArray sound_buffer;
        while (true) {
            uint32_t num_read = reader->Read(max_samples_per_read);
            if (num_read == 0) {
                break;
            }
    
            for (int i = 0;  i < reader->GetNumTrackReaders(); i++) {
                MXFTrackReader *track_reader = reader->GetTrackReader(i);
                const MXFTrackInfo *input_track_info = track_reader->GetTrackInfo();
                const MXFSoundTrackInfo *sound_info = dynamic_cast<const MXFSoundTrackInfo*>(input_track_info);
    
                switch (input_track_info->essence_type) {
                case EssenceType::WAVE_PCM:
                    {
                        while(true) {
                            Frame *frame = track_reader->GetFrameBuffer()->GetLastFrame(true);
                            if(!frame) {
                                break;
                            }
                            if(frame->IsEmpty()) {
                                continue;
                            }
    
                            sound_buffer.Grow(frame->GetSize());
                            auto pcm_track = output_audio_tracks[audio_track_index];
    
                            printf("output_audio_tracks[%d] %s\n", audio_track_index, pcm_track ? "ok" : "== NULL!");
    
                            auto bits_per_sample = sound_info->bits_per_sample;
                            auto channel_block_align = (bits_per_sample + 7) / 8;
    
                            for(int channel = 0; channel < sound_info->channel_count; channel++) {
                                deinterleave_audio(frame->GetBytes(), frame->GetSize(),
                                        sound_info->bits_per_sample,
                                        sound_info->channel_count, channel,
                                        sound_buffer.GetBytes(),
                                        sound_buffer.GetAllocatedSize());
    
                                sound_buffer.SetSize(frame->GetSize() / sound_info->channel_count);
    
                                size_t num_samples = frame->GetSize() / (sound_info->channel_count * channel_block_align);
    
                                printf("try WriteSamples channel=%d sound_buffer.GetSize()=%" PRId32 " num_samples=%zu frame->GetSize()=%" PRId32 "\n"
                                       , channel, sound_buffer.GetSize(), num_samples, frame->GetSize());
    
                                pcm_track->WriteSamples(channel,
                                                        sound_buffer.GetBytes(),
                                                        sound_buffer.GetSize(),
                                                        //num_samples * channel_block_align,
                                                        num_samples);
                            }
                        }
                        audio_track_index++;
                    }
                    break;
                case EssenceType::ANC_DATA:
                    {
                        Frame *frame = reader->GetTrackReader(i)->GetFrameBuffer()->GetLastFrame(true);
                        output_anc_track->WriteSamples(0,(unsigned char*) frame->GetBytes(), frame->GetSize(),1);
                    }
                    break;
                case EssenceType::IEC_DV25:
                case EssenceType::DV100_1080I:
                    {
                        Frame *frame = reader->GetTrackReader(i)->GetFrameBuffer()->GetLastFrame(true);
                        output_video_track->WriteSamples(0,(unsigned char*) frame->GetBytes(), frame->GetSize(), 1);
                    }
                    break;
                default:
                    printf("Unknown essence type %s\n", essence_type_to_string(input_track_info->essence_type));
                    throw false;
                }
            }
            audio_track_index = 0;
        }
    
    
        delete clip;
    
        printf("===== finish =====\n");
        return 0;
    }
    
     

    Last edit: Sergey Romashev 2017-07-25
  • Philip de Nier

    Philip de Nier - 2017-07-26

    The issue is that you haven't registered all the track channels in the OutputTrack, i.e. you need to call OutputTrack::AddInput for each channel. The result is that OutputTrack only thinks 1 channel of audio is present (it needs to know how the channels are mapped and so doesn't query the ClipWriterTrack for the channel count) in the track and calls ClipWriterTrack::WriteSamples after receiving 1 channel of audio samples. This results in the exception because there is insufficient data for >1 channels.

    However, given that you want to copy the samples unchanged you should just call ClipWriterTrack::WriteSamples using the Frame data, i.e. no need to use the OutputTrack which is intended to support remapping audio channels.

    Philip

     
  • Sergey Romashev

    Sergey Romashev - 2017-07-27

    Much Thanks, Philip.
    How can i create ClipWriterTrack without OutputTrack?

     
  • Philip de Nier

    Philip de Nier - 2017-07-27

    Using ClipWriter::CreateTrack.

    Philip

     
  • Sergey Romashev

    Sergey Romashev - 2017-07-27

    Thanks.

     
MongoDB Logo MongoDB