Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 54 additions & 25 deletions IsoLib/t35_tool/extraction/MebxMe4cExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -213,41 +213,70 @@ static MP4Err findMebxMe4cTrackReader(MP4Movie moov, const std::string &t35Prefi

if(setupInfoSize > 0)
{
// Parse setupInfo binary format:
// 1. utf8string description (null-terminated)
// 2. unsigned int(8) t35_identifier[] (remaining bytes)

char *setupData = (char *)*setupInfoH;

// Read null-terminated description
size_t descLen = 0;
for(size_t i = 0; i < setupInfoSize; i++)
// Simulate the box size and 4CC type, and the reserved and dataReferenceIndex fields
// to reuse ISOGetT35SampleEntryFields() and ISOGetFirstHumanReadableStreamDescription()
u32 it35SampleEntryHeaderSize = 4 + 4 + 6 + 2;
u32 it35SampleEntrySize = it35SampleEntryHeaderSize + setupInfoSize;
MP4Handle it35SampleEntryH = nullptr;
err = MP4NewHandle(it35SampleEntryHeaderSize, &it35SampleEntryH);
if(err)
{
if(setupData[i] == '\0')
{
descLen = i;
break;
}
LOG_ERROR("Failed to create it35SampleEntryH handle (err={})", err);
MP4DisposeHandle(setupInfoH);
MP4DisposeHandle(read_key_value);
continue;
}

std::string desc;
if(descLen > 0)
char *it35SampleEntryData = (char *)*it35SampleEntryH;
it35SampleEntryData[0] = (it35SampleEntrySize >> 24) & 0xFF; // box size
it35SampleEntryData[1] = (it35SampleEntrySize >> 16) & 0xFF;
it35SampleEntryData[2] = (it35SampleEntrySize >> 8) & 0xFF;
it35SampleEntryData[3] = (it35SampleEntrySize >> 0) & 0xFF;
memcpy(&it35SampleEntryData[4], keyPtr, 4); // 'it35'
memset(&it35SampleEntryData[4 + 4], 0, 6); // reserved
memset(&it35SampleEntryData[4 + 4 + 6], 0, 2); // dataReferenceIndex
err = MP4HandleCat(it35SampleEntryH, setupInfoH); // unsigned int(8) t35_identifier_length
// unsigned int(8) t35_identifier[]
// Optional hrsd box
if(err)
{
desc = std::string(setupData, descLen);
LOG_ERROR("Failed to write to it35SampleEntryH handle (err={})", err);
MP4DisposeHandle(it35SampleEntryH);
MP4DisposeHandle(setupInfoH);
MP4DisposeHandle(read_key_value);
continue;
}

// Read remaining bytes as t35_identifier
u32 identifierStart = descLen + 1; // Skip null terminator
u32 identifierSize = setupInfoSize - identifierStart;
u8 *identifier = nullptr;
u32 identifierLength = 0;
char *description = NULL;
MP4Err readErr =
ISOGetT35SampleEntryFields(it35SampleEntryH, &identifier, &identifierLength);
MP4Err hrsdErr = ISOGetFirstHumanReadableStreamDescription(it35SampleEntryH, &description);

MP4DisposeHandle(it35SampleEntryH);

std::vector<uint8_t> identifierBytes;
if(identifierSize > 0 && identifierStart < setupInfoSize)
std::string desc;

if(readErr)
{
LOG_WARN("Could not read t35_identifier from mebx me4c it35");
}
else
{
identifierBytes.assign((uint8_t *)(setupData + identifierStart),
(uint8_t *)(setupData + setupInfoSize));
identifierBytes.assign(identifier, identifier + identifierLength);
if(hrsdErr)
{
LOG_WARN("Could not read HumanReadableStreamDescription");
}
else if(description)
{
desc = description;
}
}
free(identifier);
free(description);

// Convert identifier bytes to hex string
std::string hexStr = T35Prefix::bytesToHex(identifierBytes);

LOG_DEBUG(" Parsed setupInfo: description='{}', identifier={} ({} bytes)",
Expand Down
54 changes: 22 additions & 32 deletions IsoLib/t35_tool/injection/MebxMe4cStrategy.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -268,51 +268,41 @@ MP4Err MebxMe4cStrategy::inject(const InjectionConfig &config, const MetadataMap
LOG_DEBUG("Created key_value handle with it35 4CC");

// Build setupInfo with T.35 prefix in binary format:
// 1. utf8string description (null-terminated, '\0' if empty)
// 1. unsigned int(8) t35_identifier_length
// 2. unsigned int(8) t35_identifier[] (binary bytes)
MP4Handle setupInfo = nullptr;
{
const std::string &desc = prefix.description();
std::vector<uint8_t> identifierBytes = prefix.toBytes();

// Calculate total size: description length + null terminator + identifier bytes
u32 descLen = desc.empty() ? 1 : (u32)desc.size() + 1; // '\0' if empty, or string + '\0'
u32 totalSize = descLen + (u32)identifierBytes.size();

err = MP4NewHandle(totalSize, &setupInfo);
LOG_DEBUG("Creating temporary it35 sample entry");
MP4T35MetadataSampleEntryPtr it35 = nullptr;
u32 dataReferenceIndex = 0; // unused
err = ISONewT35SampleDescription(&it35, dataReferenceIndex, prefix.toString().c_str());
if(err)
{
LOG_ERROR("Failed to create setupInfo handle (err={})", err);
MP4DisposeHandle(key_value);
LOG_ERROR("Failed to create temporary it35 sample description (err={})", err);
return err;
}

char *buffer = *setupInfo;
u32 offset = 0;

// Write description as null-terminated UTF-8 string
if(desc.empty())
{
buffer[offset++] = '\0'; // Just null byte if no description
}
else
err = MP4NewHandle(0, &setupInfo);
if(err)
{
memcpy(buffer + offset, desc.c_str(), desc.size());
offset += desc.size();
buffer[offset++] = '\0'; // Null terminator
LOG_ERROR("Failed to create setupInfo handle (err={})", err);
MP4DisposeHandle(key_value);
return err;
}

// Write t35_identifier as binary bytes
if(!identifierBytes.empty())
err = atomPtrToSampleEntryH(setupInfo, (MP4AtomPtr)it35);
if(err)
{
memcpy(buffer + offset, identifierBytes.data(), identifierBytes.size());
offset += identifierBytes.size();
LOG_ERROR("Failed to convert temporary it35 sample entry to (err={})", err);
MP4DisposeHandle(key_value);
MP4DisposeHandle(setupInfo);
return err;
}

LOG_DEBUG("Created setupInfo handle: description='{}' ({} bytes), identifier={} bytes",
desc.empty() ? "(empty)" : desc, descLen, identifierBytes.size());
}

// Skip the box size and 'it35' type, and the reserved and dataReferenceIndex fields
err = MP4SetHandleOffset(setupInfo, 4 + 4 + 6 + 2);
if(err) return err;

// Add sample entry with me4c namespace
// For me4c namespace, desired_local_key_id must match the 4CC in key_value
u32 desired_key_id = MP4_FOUR_CHAR_CODE('i', 't', '3', '5');
Expand All @@ -324,7 +314,7 @@ MP4Err MebxMe4cStrategy::inject(const InjectionConfig &config, const MetadataMap
MP4_FOUR_CHAR_CODE('m', 'e', '4', 'c'), // me4c namespace
key_value, // 'it35' 4CC
NULL, // locale_string (not used)
setupInfo); // T.35 prefix string
setupInfo); // T.35 prefix string and optional hrsd box

MP4DisposeHandle(key_value);
MP4DisposeHandle(setupInfo);
Expand Down
Loading