Menu

video bit rate and bit depth had changed after copying the file

2018-06-20
2018-06-25
  • Sergey Romashev

    Sergey Romashev - 2018-06-20

    I'm trying to copy a file.
    Bit rate of video had changed in the copied file.
    After copying another file, the bit depth changes.

    Is there any way to fix this issues?

    Source file1:

    Video
    ID                                       : 2
    Format                                   : MPEG Video
    Commercial name                          : XDCAM HD422
    Format version                           : Version 2
    Format profile                           : 4:2:2@High
    Format settings                          : CustomMatrix / BVOP
    Format settings, BVOP                    : Yes
    Format settings, Matrix                  : Custom
    Format settings, GOP                     : M=3, N=12
    Format settings, picture structure       : Frame
    Format settings, wrapping mode           : Frame
    Codec ID                                 : 0D01030102046001-0401020201040300
    Duration                                 : 4 min 14 s
    Bit rate mode                            : Constant
    Bit rate                                 : 50.0 Mb/s
    Width                                    : 1 920 pixels
    Height                                   : 1 080 pixels
    Display aspect ratio                     : 16:9
    Active Format Description                : 0
    Frame rate                               : 25.000 FPS
    Standard                                 : Component
    Color space                              : YUV
    Chroma subsampling                       : 4:2:2
    Bit depth                                : 8 bits
    Scan type                                : Interlaced
    Scan order                               : Top Field First
    Compression mode                         : Lossy
    Bits/(Pixel*Frame)                       : 0.965
    Time code of first frame                 : 00:00:00:00
    Time code source                         : Group of pictures header
    GOP, Open/Closed                         : Open
    GOP, Open/Closed of first frame          : Closed
    Stream size                              : 1.48 GiB (91%)
    Color primaries                          : BT.709
    Transfer characteristics                 : BT.709
    Matrix coefficients                      : BT.709
    

    Copied file1:

    Bit rate                                 : 105 Mb/s
    

    Source file2:

    Video
    ID                                       : 2
    Format                                   : DV
    Commercial name                          : DVCPRO HD
    Format settings, wrapping mode           : Frame
    Codec ID                                 : 0D01030102026101-0401020202020600
    Duration                                 : 21 s 720 ms
    Bit rate                                 : 116 Mb/s
    Width                                    : 1 440 pixels
    Height                                   : 1 080 pixels
    Display aspect ratio                     : 16:9
    Active Format Description                : Letterbox image with an aspect ratio greater than 16:9
    Frame rate mode                          : Constant
    Frame rate                               : 25.000 FPS
    Standard                                 : PAL
    Color space                              : YUV
    Chroma subsampling                       : 4:2:2
    Bit depth                                : 8 bits
    Scan type                                : Interlaced
    Scan order                               : Top Field First
    Compression mode                         : Lossy
    Bits/(Pixel*Frame)                       : 2.976
    Time code of first frame                 : 00:07:29:07
    Time code source                         : Subcode time code
    Stream size                              : 300 MiB (96%)
    Title                                    : Picture
    Transfer characteristics                 : BT.601
    

    Copied file2:

    Bit depth                                : 10 bits
    

    My code:

    void copy(const std::string &srcFileName, const std::string &dstFileName)
    {
        Timecode start_timecode;
        uint32_t max_samples_per_read = 1;
        AppMXFFileFactory file_factory;
        bmx::ByteArray sound_buffer;
        bmx::ByteArray normalized_buffer;
        bmx::ByteArray write_buffer;
        auto reader = std::make_shared<MXFFileReader>();
    
        reader->SetFileFactory(&file_factory, false);
        reader->GetPackageResolver()->SetFileFactory(&file_factory, false);
    
        MXFFileReader::OpenResult result;
        result = reader->Open(srcFileName);
        int mxfVersion = reader->GetMXFVersion();
        if (result != MXFFileReader::OpenResult::MXF_RESULT_SUCCESS) {
            std::string msg = Poco::format("Unable to open source file. Status %d", result);
            throw std::runtime_error(msg);
        }
        auto clipType = detectClipType(reader);
        //Prepare for writing results
        ClipWriterTrack* out_video_track = nullptr;
        ClipWriterTrack* out_anc_track = nullptr;
        std::map<int, ClipWriterTrack*> out_audio_tracks;
    
        mxfpp::File* file;
        try {
            file = file_factory.OpenNew(dstFileName);
    
        }
        catch (...) {
            std::string msg = Poco::format("Unable to open destination file %s", dstFileName);
            throw std::runtime_error(msg);
        }
    
        int16_t mxfFlavour;
        std::shared_ptr<ClipWriter> clip;
        if (clipType == ClipWriterType::CW_OP1A_CLIP_TYPE) {
            mxfFlavour = OP1A_MIN_PARTITIONS_FLAVOUR;
    
            if (mxfVersion == MXF_PREFACE_VER(1, 2)) {
                mxfFlavour |= OP1A_377_2004_FLAVOUR;
            }
    
            clip.reset(ClipWriter::OpenNewOP1AClip(mxfFlavour, file, reader->GetEditRate()));
            auto op1a = clip->GetOP1AClip();
            op1a->SetAddSystemItem(true);
        }
        else {
            mxfFlavour = D10_DEFAULT_FLAVOUR;
            clip.reset(ClipWriter::OpenNewD10Clip(mxfFlavour, file, reader->GetEditRate()));
        }
    
        clip->ReserveHeaderMetadataSpace(16384);
        start_timecode.Init(reader->GetEditRate(), false);
        clip->SetStartTimecode(start_timecode);
        setProductInfo(clip);
    
        //Creating tracks
        int audio_track_index = 0;
    
        for (int i = 0; i < reader->GetNumTrackReaders(); i++) {
            MXFTrackReader *track_reader = reader->GetTrackReader(i);
            const MXFTrackInfo *input_track_info = track_reader->GetTrackInfo();
            bmx::EssenceType essenceType = input_track_info->essence_type;
            const MXFPictureTrackInfo *inputPictureInfo = nullptr;
    
            if (isSupportedVideoEssenceType(essenceType)) {
                inputPictureInfo = dynamic_cast<const MXFPictureTrackInfo*>(input_track_info);
            }
    
            switch (essenceType) {
            case EssenceType::WAVE_PCM:
            case EssenceType::D10_AES3_PCM:
            {
                ClipWriterTrack* track = clip->CreateTrack(EssenceType::WAVE_PCM);
                out_audio_tracks[audio_track_index] = track;
    
                const MXFSoundTrackInfo *input_sound_info = dynamic_cast<const MXFSoundTrackInfo*>(input_track_info);
                track->SetSamplingRate(input_sound_info->sampling_rate);
                track->SetQuantizationBits(input_sound_info->bits_per_sample);
                track->SetChannelCount(input_sound_info->channel_count);
                track->SetAES3Mapping(true);
                track->SetLocked(true);
                if (essenceType == EssenceType::WAVE_PCM) {
                    track->SetOutputTrackNumber(i + 1);
                }
    
                audio_track_index++;
            }
            break;
            case EssenceType::DV100_1080I: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(10);
            }
                                           break;
            case EssenceType::IEC_DV25: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(8);
            }
                                        break;
            // D10 - clip
            case EssenceType::D10_30:
            case EssenceType::D10_40:
            case EssenceType::D10_50: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(8);
                out_video_track->SetAspectRatio(inputPictureInfo->aspect_ratio);
            }
                                      break;
            case EssenceType::MPEG2LG_422P_HL_1080P:
            case EssenceType::MPEG2LG_422P_HL_1080I: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(8);
            }
                                                     break;
            case EssenceType::MPEG2LG_MP_HL_1920_1080I:
            case EssenceType::MPEG2LG_MP_HL_1920_1080P:
            case EssenceType::MPEG2LG_MP_HL_1440_1080I:
            case EssenceType::MPEG2LG_MP_HL_1440_1080P:
            case EssenceType::MPEG2LG_MP_H14_1080I:
            case EssenceType::MPEG2LG_MP_H14_1080P: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(8);
            }
                                                    break;
            case EssenceType::MPEG2_422P_ML_LongGOP: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(inputPictureInfo->component_depth);
            }
                                                     break;
            case EssenceType::AVCI100_1080I:
            case EssenceType::AVCI100_1080P:
            case EssenceType::AVCI50_1080I:
            case EssenceType::AVCI50_1080P: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(10);
            }
                                            break;
            case EssenceType::VC3_1080I_1242: {
                out_video_track = clip->CreateTrack(essenceType);
                out_video_track->SetComponentDepth(inputPictureInfo->component_depth);
            }
                                              break;
            case EssenceType::ANC_DATA: {
                if (clipType == ClipWriterType::CW_D10_CLIP_TYPE) {
                    printf("Currently unable to write anc-data to d10-clips\n"); //known issue
                    break;
                }
                reader->SetTemporaryFrameBuffer(true);
                out_anc_track = clip->CreateTrack(essenceType);
                uint32_t num_read = reader->Read(max_samples_per_read);
                if (num_read) {
                    std::shared_ptr<Frame> anc_frame;
                    anc_frame.reset(
                        track_reader->GetFrameBuffer()->GetLastFrame(true));
                    out_anc_track->SetConstantDataSize(anc_frame->GetSize());
                }
                reader->SetTemporaryFrameBuffer(false);
                reader->Seek(0);
            }
                                        break;
            default: {
                std::string errMsg("Unsupported essense format");
                errMsg += " '" + std::string(essence_type_to_enum_string(essenceType)) + "'";
                file->closeMemoryFile();
                /* file is automatically deleted by ClipWriter */
                throw std::runtime_error(errMsg);
            }
                     break;
            }
        }
    
        clip->PrepareHeaderMetadata();
        clip->PrepareWrite();
    
        long totalRead = 0l;
        audio_track_index = 0;
    
        while (true) {
            uint32_t num_read = reader->Read(max_samples_per_read);
            if (num_read == 0) {
                if (reader->ReadError())
                {
                    std::string errMsg = reader->ReadErrorMessage();
                    throw std::runtime_error(errMsg);
                }
                else
                {
                    break;
                }
            }
            totalRead += num_read;
    
            //Enumerating tracks
            for (int i = 0; i < reader->GetNumTrackReaders(); i++) {
                MXFTrackReader *track_reader = reader->GetTrackReader(i);
    
                if (!track_reader->IsEnabled())
                    continue;
    
    
                const MXFTrackInfo *input_track_info = track_reader->GetTrackInfo();
    
                bmx::EssenceType essenceType = input_track_info->essence_type;
    
                const MXFSoundTrackInfo *input_sound_info =
                    dynamic_cast<const MXFSoundTrackInfo*>(input_track_info);
    
                if (essenceType == WAVE_PCM || essenceType == EssenceType::D10_AES3_PCM) {
                    Rational sampling_rate = input_sound_info->sampling_rate;
                    double samples_per_second = ((double)sampling_rate.numerator) / sampling_rate.numerator;
                    while (true) {
                        const MXFSoundTrackInfo *sound_info =
                            dynamic_cast<const MXFSoundTrackInfo*>(input_track_info);
    
                        std::shared_ptr<Frame> frame;
                        frame.reset(
                            reader->GetTrackReader(i)->GetFrameBuffer()->GetLastFrame(
                                true));
                        if (!frame) {
                            break;
                        }
                        if (frame->IsEmpty()) {
                            continue;
                        }
    
                        auto bits_per_sample = input_sound_info->bits_per_sample;
                        auto channel_block_align = (bits_per_sample + 7) / 8;
                        uint32_t track_buffer_size = frame->GetSize();
                        uint32_t channel_buffer_size = frame->GetSize() / sound_info->channel_count;
                        size_t num_samples = channel_buffer_size / channel_block_align;
    
                        sound_buffer.Grow(channel_buffer_size);
                        sound_buffer.SetSize(channel_buffer_size);
                        normalized_buffer.Reallocate(channel_buffer_size);
                        write_buffer.Grow(track_buffer_size);
                        ClipWriterTrack* track = out_audio_tracks[audio_track_index];
    
                        for (int c = 0; c < sound_info->channel_count; c++) {
                            // extract
                            if (essenceType == EssenceType::D10_AES3_PCM) {
                                convert_aes3_to_pcm(frame->GetBytes(),
                                    track_buffer_size, true, bits_per_sample, c,
                                    sound_buffer.GetBytes(),
                                    channel_buffer_size);
                                num_samples = get_aes3_sample_count(frame->GetBytes(), frame->GetSize());
                            }
                            else {
    
                                deinterleave_audio(frame->GetBytes(),
                                    track_buffer_size, bits_per_sample,
                                    sound_info->channel_count, c,
                                    sound_buffer.GetBytes(),
                                    channel_buffer_size);
                            }
    
                            normalized_buffer.CopyBytes(sound_buffer.GetBytes(), channel_buffer_size);
    
                            interleave_audio(normalized_buffer.GetBytes(), channel_buffer_size,
                                bits_per_sample,
                                sound_info->channel_count, c,
                                write_buffer.GetBytes(),
                                track_buffer_size);
    
                        }
    
                        track->WriteSamples(write_buffer.GetBytes(), track_buffer_size, num_samples);
                    }
                    audio_track_index++;
                }
                else if (essenceType == EssenceType::ANC_DATA) {
    
                    if (clipType == ClipWriterType::CW_D10_CLIP_TYPE) {
                        printf("Anc-data tracks are not supported for d10-clips\n"); //known issue
                        continue;
                    }
    
                    std::shared_ptr<Frame> frame;
                    frame.reset(reader->GetTrackReader(i)->GetFrameBuffer()->GetLastFrame(true));
                    if (out_anc_track) {
                        out_anc_track->WriteSamples((unsigned char*)frame->GetBytes(), frame->GetSize(), 1);
                    }
                    continue;
                }
                else {
                    if (!isSupportedVideoEssenceType(essenceType)) {
                        printf("Unknown essence codec! %s\n", essence_type_to_string(essenceType));
                        continue;
                    }
    
                    std::shared_ptr<Frame> frame;
                    frame.reset(reader->GetTrackReader(i)->GetFrameBuffer()->GetLastFrame(true));
                    if (out_video_track) {
                        out_video_track->WriteSamples((unsigned char*)frame->GetBytes(), frame->GetSize(), 1);
                    }
                    continue;
                }
            }
            audio_track_index = 0;
        }
    
        // close op1a file
        clip->CompleteWrite();
    
        if (!totalRead) {
            throw std::runtime_error("Unable to write file");
        }
    }
    
     
  • Philip de Nier

    Philip de Nier - 2018-06-20

    I don't know what information mediainfo uses for the reported bit rate. When bmx transwraps an MXF file it will extract the bit rate metadata from the MPEG-2 video bitstream, ie. it will not copy across the input file's MXF metadata. My guess therefore is that the bitstream has bit rate metadata != 50Mb/s or no bit rate metadata.

    You can check this by extracting frames from the input (eg. 30) and then running the parser utility showing what bmx has found:

    mxf2raw -p /tmp/test --dur 30 input.mxf
    bmxparse m2v /tmp/test_v0.raw
    

    In a frame with metadata sequence_header: true there will be a bit_rate (or not) which when multiplied by 400 gives you bit rate, eg. 125000 is for 50Mb/s.

    The DVC-Pro HD 10 bit depth is hardcoded in your software: out_video_track->SetComponentDepth(10);.

    Philip

     
  • Sergey Romashev

    Sergey Romashev - 2018-06-21

    Thank you Philip.
    Your advice had helped with bit depth issue of course.
    Also I took advantage of your advice on the bit rate issue.
    bmxparse had showed the equal results for the input and output file.

    Frame #0:
      sequence_header    : true
      bit_rate           : 262143   /*105 Mb/s*/
    ...
    Frame #6:
      sequence_header    : true
      bit_rate           : 125000   /*50 Mb/s*/
    ...
    Frame #18:
      sequence_header    : true
      bit_rate           : 125000
    ...
    

    I looked at the output of MediaInfo in debug mode.

    Source file:

    00001576 MPEG-2 Video Descriptor (240 bytes)
    00001576  Header (20 bytes)
    00001576   Code (16 bytes)
    00001576    Start (0x06):                        6 (0x06)
    ...
    00001659  Maximum bit rate - 50000000 (0x2FAF080) (8 bytes)
    00001659   Header (4 bytes)
    00001659    Code:                                32768 (0x8000)
    0000165B    Length:                              4 (0x0004)
    0000165D   Data:                                 50000000 (0x02FAF080)
    

    Copied file:

    00001056 MPEG-2 Video Descriptor (350 bytes)
    00001056  Header (20 bytes)
    00001056   Code (16 bytes)
    00001056    Start (0x06):                        6 (0x06)
    ...
    000011A0  Maximum bit rate - 104857200 (0x63FFE70) (8 bytes)
    000011A0   Header (4 bytes)
    000011A0    Code:                                65526 (0xFFF6)
    000011A2    Length:                              4 (0x0004)
    000011A4   Data:                                 104857200 (0x063FFE70)
    

    It looks like i need to get to MPEGVideoDescriptor.
    Perhaps enough to copy value from the input's descriptor to the output's descriptor.
    But i couldn't to figure out how to do it.
    Point the right direction please.

     
  • Philip de Nier

    Philip de Nier - 2018-06-22

    OK, so I assume that the last GOP in the file also has 105Mb/s set in the bitstream and that value is the last one extracted by the writer helper before it is set in the descriptor in the track writer.

    In your code you have access to the MXF file descriptor via the MXFTrackReader::GetFileDescriptor() method. The output file descriptor is available through the output track ClipWriterTrack::GetMXFDescriptorHelper() and then calling GetFileDescriptor(). Cast the objects to the MPEGVideoDescriptor to get and set the bit rate property. You also need to modify the track writer so that it only sets the bit rate if it has not already been set (ie. by you) by using MPEGVideoDescriptor::haveBitRate().

    Philip

     
  • Sergey Romashev

    Sergey Romashev - 2018-06-25

    Yes, you are right. First and last GOP has 105Mb/s. All others has 50Mb/s bitrate.
    Thank you. This is the solution.

     
MongoDB Logo MongoDB