Skip to content

Commit

Permalink
Merge pull request #102 from bbc/philipn-anc-vbi-klv
Browse files Browse the repository at this point in the history
raw2bmx: Add support for ANC/VBI frame wrapped in KLV
  • Loading branch information
philipnbbc authored Nov 11, 2024
2 parents 9a79daf + 1fdb436 commit c01bc02
Show file tree
Hide file tree
Showing 7 changed files with 227 additions and 23 deletions.
51 changes: 40 additions & 11 deletions apps/raw2bmx/raw2bmx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@
#include <bmx/essence_parser/RawEssenceReader.h>
#include <bmx/essence_parser/FileEssenceSource.h>
#include <bmx/essence_parser/KLVEssenceSource.h>
#include <bmx/essence_parser/KLVEssenceReader.h>
#include <bmx/essence_parser/FilePatternEssenceSource.h>
#include <bmx/essence_parser/D10RawEssenceReader.h>
#include <bmx/essence_parser/MPEG2AspectRatioFilter.h>
Expand Down Expand Up @@ -153,6 +154,7 @@ struct RawInput

RawEssenceReader *raw_reader;
WaveReader *wave_reader;
KLVEssenceReader *klv_reader;
uint32_t channel_count;
TimedTextManifestParser *timed_text_manifest;

Expand Down Expand Up @@ -256,14 +258,20 @@ static uint32_t read_samples(RawInput *input, uint32_t max_samples_per_read)
uint32_t num_frame_samples = input->sample_sequence[input->sample_sequence_offset];
input->sample_sequence_offset = (input->sample_sequence_offset + 1) % input->sample_sequence_size;

if (input->raw_reader)
if (input->raw_reader) {
return (input->raw_reader->ReadSamples(num_frame_samples) == num_frame_samples ? 1 : 0);
else
} else if (input->klv_reader) {
BMX_ASSERT(num_frame_samples == 1);
return (input->klv_reader->ReadValue() ? 1 : 0);
} else {
return (input->wave_reader->Read(num_frame_samples) == num_frame_samples ? 1 : 0);
}
} else {
BMX_ASSERT(input->sample_sequence_size == 1 && input->sample_sequence[0] == 1);
if (input->raw_reader)
return input->raw_reader->ReadSamples(max_samples_per_read);
else if (input->klv_reader)
return (input->klv_reader->ReadValue() ? 1 : 0);
else
return input->wave_reader->Read(max_samples_per_read);
}
Expand Down Expand Up @@ -327,6 +335,12 @@ static bool open_raw_reader(RawInput *input)
{
input->raw_reader = new D10RawEssenceReader(essence_source);
}
else if (input->parse_klv &&
(input->essence_type == ANC_DATA ||
input->essence_type == VBI_DATA))
{
input->klv_reader = new KLVEssenceReader(dynamic_cast<KLVEssenceSource*>(essence_source));
}
else
{
input->raw_reader = new RawEssenceReader(essence_source);
Expand Down Expand Up @@ -392,6 +406,7 @@ static void clear_input(RawInput *input)
{
delete input->raw_reader;
delete input->wave_reader;
delete input->klv_reader;
delete input->filter;
delete input->timed_text_manifest;
delete input->wave_chunk_refs;
Expand Down Expand Up @@ -834,8 +849,8 @@ static void usage(const char *cmd)
printf(" --vc3_1080i_1260 <name> Raw VC3/DNxHD 1920x1080i 85 Mbps input file\n");
printf(" --pcm <name> Raw PCM audio input file\n");
printf(" --wave <name> Wave PCM audio input file\n");
printf(" --anc <name> Raw ST 436 Ancillary data. Currently requires the --anc-const option\n");
printf(" --vbi <name> Raw ST 436 Vertical Blanking Interval data. Currently requires the --vbi-const option\n");
printf(" --anc <name> Raw ST 436 Ancillary data. Requires the --anc-const option or frame wrapped in KLV and the --klv option\n");
printf(" --vbi <name> Raw ST 436 Vertical Blanking Interval data. Requires the --vbi-const option or frame wrapped in KLV and the --klv option\n");
printf(" --tt <manifest> Manifest file containing Timed Text metadata\n");
printf("\n\n");
printf("Notes:\n");
Expand Down Expand Up @@ -4045,10 +4060,10 @@ int main(int argc, const char** argv)
fprintf(stderr, "Multiple '%s' inputs are not permitted\n", argv[cmdln_index]);
return 1;
}
if (input.anc_const_size == 0)
if (input.anc_const_size == 0 && !input.parse_klv)
{
usage_ref(argv[0]);
fprintf(stderr, "Missing or zero '--anc-const' option for input '%s'\n", argv[cmdln_index]);
fprintf(stderr, "Missing or zero '--anc-const' or '--klv' options for input '%s'\n", argv[cmdln_index]);
return 1;
}
input.essence_type = ANC_DATA;
Expand All @@ -4071,7 +4086,7 @@ int main(int argc, const char** argv)
fprintf(stderr, "Multiple '%s' inputs are not permitted\n", argv[cmdln_index]);
return 1;
}
if (input.vbi_const_size == 0)
if (input.vbi_const_size == 0 && !input.parse_klv)
{
usage_ref(argv[0]);
fprintf(stderr, "Missing or zero '--vbi-const' option for input '%s'\n", argv[cmdln_index]);
Expand Down Expand Up @@ -5593,10 +5608,12 @@ int main(int argc, const char** argv)
clip_track->SetChannelAssignment(audio_layout_mode_label);
break;
case ANC_DATA:
clip_track->SetConstantDataSize(input->anc_const_size);
if (input->anc_const_size)
clip_track->SetConstantDataSize(input->anc_const_size);
break;
case VBI_DATA:
clip_track->SetConstantDataSize(input->vbi_const_size);
if (input->vbi_const_size)
clip_track->SetConstantDataSize(input->vbi_const_size);
break;
case TIMED_TEXT:
clip_track->SetTimedTextSource(input->timed_text_manifest);
Expand Down Expand Up @@ -5863,12 +5880,14 @@ int main(int argc, const char** argv)
case ANC_DATA:
input->sample_sequence[0] = 1;
input->sample_sequence_size = 1;
input->raw_reader->SetFixedSampleSize(input->anc_const_size);
if (input->raw_reader && input->anc_const_size)
input->raw_reader->SetFixedSampleSize(input->anc_const_size);
break;
case VBI_DATA:
input->sample_sequence[0] = 1;
input->sample_sequence_size = 1;
input->raw_reader->SetFixedSampleSize(input->vbi_const_size);
if (input->raw_reader && input->vbi_const_size)
input->raw_reader->SetFixedSampleSize(input->vbi_const_size);
break;
case TIMED_TEXT:
break;
Expand Down Expand Up @@ -6206,6 +6225,16 @@ int main(int argc, const char** argv)
input->raw_reader->GetSampleData(), input->raw_reader->GetSampleDataSize(),
num_samples);
}
} else if (input->klv_reader) {
num_samples = input->klv_reader->GetValueSize() ? 1 : 0;
if (num_samples) {
output_track->WriteSamples(
output_channel_index,
input->klv_reader->GetValue(),
input->klv_reader->GetValueSize(),
num_samples
);
}
} else {
Frame *frame = input->wave_reader->GetTrack(input_channel_index)->GetFrameBuffer()->GetLastFrame(false);
BMX_ASSERT(frame);
Expand Down
1 change: 1 addition & 0 deletions include/bmx/essence_parser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ list(APPEND bmx_headers
bmx/essence_parser/FileEssenceSource.h
bmx/essence_parser/FilePatternEssenceSource.h
bmx/essence_parser/J2CEssenceParser.h
bmx/essence_parser/KLVEssenceReader.h
bmx/essence_parser/KLVEssenceSource.h
bmx/essence_parser/MJPEGEssenceParser.h
bmx/essence_parser/MPEG2AspectRatioFilter.h
Expand Down
60 changes: 60 additions & 0 deletions include/bmx/essence_parser/KLVEssenceReader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
/*
* Copyright (C) 2024, British Broadcasting Corporation
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the British Broadcasting Corporation nor the names
* of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifndef BMX_KLV_ESSENCE_READER_H_
#define BMX_KLV_ESSENCE_READER_H_

#include <bmx/essence_parser/KLVEssenceSource.h>
#include <bmx/ByteArray.h>


namespace bmx
{

class KLVEssenceReader
{
public:
KLVEssenceReader(KLVEssenceSource *essence_source);
~KLVEssenceReader();

uint32_t ReadValue();

unsigned char* GetValue() const { return mValueBuffer.GetBytes(); }
uint32_t GetValueSize() const { return mValueBuffer.GetSize(); }

private:
KLVEssenceSource *mEssenceSource;
ByteArray mValueBuffer;
};


};


#endif
6 changes: 6 additions & 0 deletions include/bmx/essence_parser/KLVEssenceSource.h
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,11 @@ class KLVEssenceSource : public EssenceSource
virtual int GetErrno() const;
virtual std::string GetStrError() const;

public:
bool PositionInV(uint64_t *size);

uint64_t GetOffsetInV() const { return mValueLen - mRemValueLen; }

private:
typedef enum
{
Expand All @@ -73,6 +78,7 @@ class KLVEssenceSource : public EssenceSource
uint32_t mTrackNum;
KLVState mState;
uint64_t mValueLen;
uint64_t mRemValueLen;
};


Expand Down
1 change: 1 addition & 0 deletions src/essence_parser/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ list(APPEND bmx_sources
essence_parser/FileEssenceSource.cpp
essence_parser/FilePatternEssenceSource.cpp
essence_parser/J2CEssenceParser.cpp
essence_parser/KLVEssenceReader.cpp
essence_parser/KLVEssenceSource.cpp
essence_parser/MJPEGEssenceParser.cpp
essence_parser/MPEG2AspectRatioFilter.cpp
Expand Down
82 changes: 82 additions & 0 deletions src/essence_parser/KLVEssenceReader.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
/*
* Copyright (C) 2024, British Broadcasting Corporation
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the British Broadcasting Corporation nor the names
* of its contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#define __STDC_LIMIT_MACROS

#include <libMXF++/MXF.h>

#include <bmx/essence_parser/KLVEssenceReader.h>
#include <bmx/BMXException.h>
#include <bmx/Logging.h>

using namespace std;
using namespace bmx;


KLVEssenceReader::KLVEssenceReader(KLVEssenceSource *essence_source)
{
mEssenceSource = essence_source;
}

KLVEssenceReader::~KLVEssenceReader()
{
}

uint32_t KLVEssenceReader::ReadValue()
{
// Position at the next non-zero Value
uint64_t v_size = 0;
while (v_size == 0) {
if (!mEssenceSource->PositionInV(&v_size) || v_size > UINT32_MAX) {
if (v_size > UINT32_MAX)
log_warn("KLV value size %" PRIu64 " > max uint32 is not supported\n", v_size);
mValueBuffer.SetSize(0);
return 0;
}
}

// Expect to be at the start of the V because the read below reads the whole V
BMX_CHECK(mEssenceSource->GetOffsetInV() == 0);

mValueBuffer.Allocate(v_size);

uint32_t read_size = mEssenceSource->Read(mValueBuffer.GetBytes(), v_size);
if (read_size != v_size) {
log_warn("Incomplete KLV; only read %u of %u\n", read_size, v_size);
mValueBuffer.SetSize(0);
return 0;
}

mValueBuffer.SetSize(read_size);
return read_size;
}
Loading

0 comments on commit c01bc02

Please sign in to comment.