Skip to content

Commit

Permalink
iOS multi-stsd support
Browse files Browse the repository at this point in the history
  • Loading branch information
ireader committed Mar 30, 2019
1 parent 18df107 commit 6ae6ece
Show file tree
Hide file tree
Showing 15 changed files with 151 additions and 90 deletions.
2 changes: 1 addition & 1 deletion libdash/test/dash-static-test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static void mp4_onaudio(void* mpd, uint32_t track, uint8_t object, int channel_c
s_adapation_audio = dash_mpd_add_audio_adaptation_set((dash_mpd_t*)mpd, "dash-static-audio", object, channel_count, bit_per_sample, sample_rate, extra, bytes);
}

static void mp4_onread(void* mpd, uint32_t track, const void* buffer, size_t bytes, int64_t pts, int64_t dts)
static void mp4_onread(void* mpd, uint32_t track, const void* buffer, size_t bytes, int64_t pts, int64_t dts, int flags)
{
if (s_track_video == track)
{
Expand Down
4 changes: 3 additions & 1 deletion libmov/include/mov-atom.h
Original file line number Diff line number Diff line change
Expand Up @@ -85,9 +85,11 @@ struct mov_mdhd_t

struct mov_sample_entry_t
{
uint16_t data_reference_index; // ref [stsc] sample_description_index
uint16_t data_reference_index; // ref [dref] Data Reference Boxes
uint8_t object_type_indication; // H.264/AAC MOV_OBJECT_XXX (DecoderConfigDescriptor)
uint8_t stream_type; // MP4_STREAM_XXX
uint8_t* extra_data; // H.264 sps/pps
size_t extra_data_size;

union
{
Expand Down
2 changes: 1 addition & 1 deletion libmov/include/mov-reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ uint64_t mov_reader_getduration(mov_reader_t* mov);

/// audio: AAC raw data, don't include ADTS/AudioSpecificConfig
/// video: 4-byte data length(don't include self length) + H.264 NALU(don't include 0x00000001)
typedef void (*mov_reader_onread)(void* param, uint32_t track, const void* buffer, size_t bytes, int64_t pts, int64_t dts);
typedef void (*mov_reader_onread)(void* param, uint32_t track, const void* buffer, size_t bytes, int64_t pts, int64_t dts, int flags);
/// @return 1-read one frame, 0-EOF, <0-error
int mov_reader_read(mov_reader_t* mov, void* buffer, size_t bytes, mov_reader_onread onread, void* param);

Expand Down
20 changes: 11 additions & 9 deletions libmov/source/mov-avc1.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,26 @@
int mov_read_avcc(struct mov_t* mov, const struct mov_box_t* box)
{
struct mov_track_t* track = mov->track;
if (track->extra_data_size < box->size)
struct mov_sample_entry_t* entry = track->stsd.current;
if (entry->extra_data_size < box->size)
{
void* p = realloc(track->extra_data, (size_t)box->size);
void* p = realloc(entry->extra_data, (size_t)box->size);
if (NULL == p) return ENOMEM;
track->extra_data = p;
entry->extra_data = p;
}

mov_buffer_read(&mov->io, track->extra_data, box->size);
track->extra_data_size = (size_t)box->size;
mov_buffer_read(&mov->io, entry->extra_data, box->size);
entry->extra_data_size = (size_t)box->size;
return mov_buffer_error(&mov->io);
}

size_t mov_write_avcc(const struct mov_t* mov)
{
const struct mov_track_t* track = mov->track;
mov_buffer_w32(&mov->io, track->extra_data_size + 8); /* size */
const struct mov_sample_entry_t* entry = track->stsd.current;
mov_buffer_w32(&mov->io, entry->extra_data_size + 8); /* size */
mov_buffer_write(&mov->io, "avcC", 4);
if (track->extra_data_size > 0)
mov_buffer_write(&mov->io, track->extra_data, track->extra_data_size);
return track->extra_data_size + 8;
if (entry->extra_data_size > 0)
mov_buffer_write(&mov->io, entry->extra_data, entry->extra_data_size);
return entry->extra_data_size + 8;
}
35 changes: 20 additions & 15 deletions libmov/source/mov-esds.c
Original file line number Diff line number Diff line change
Expand Up @@ -152,23 +152,25 @@ abstract class DecoderSpecificInfo extends BaseDescriptor : bit(8)
static int mp4_read_decoder_specific_info(struct mov_t* mov, size_t len)
{
struct mov_track_t* track = mov->track;
if (track->extra_data_size < len)
struct mov_sample_entry_t* entry = track->stsd.current;
if (entry->extra_data_size < len)
{
void* p = realloc(track->extra_data, len);
void* p = realloc(entry->extra_data, len);
if (NULL == p) return ENOMEM;
track->extra_data = p;
entry->extra_data = p;
}

mov_buffer_read(&mov->io, track->extra_data, len);
track->extra_data_size = len;
mov_buffer_read(&mov->io, entry->extra_data, len);
entry->extra_data_size = len;
return mov_buffer_error(&mov->io);
}

static int mp4_write_decoder_specific_info(const struct mov_t* mov)
{
mov_write_base_descr(mov, ISO_DecSpecificInfoTag, mov->track->extra_data_size);
mov_buffer_write(&mov->io, mov->track->extra_data, mov->track->extra_data_size);
return mov->track->extra_data_size;
const struct mov_sample_entry_t* entry = mov->track->stsd.current;
mov_write_base_descr(mov, ISO_DecSpecificInfoTag, entry->extra_data_size);
mov_buffer_write(&mov->io, entry->extra_data, entry->extra_data_size);
return entry->extra_data_size;
}

// ISO/IEC 14496-1:2010(E) 7.2.6.6 DecoderConfigDescriptor (p48)
Expand All @@ -187,8 +189,9 @@ class DecoderConfigDescriptor extends BaseDescriptor : bit(8) tag=DecoderConfigD
*/
static int mp4_read_decoder_config_descriptor(struct mov_t* mov, int len)
{
mov->track->stsd.current->object_type_indication = (uint8_t)mov_buffer_r8(&mov->io); /* objectTypeIndication */
mov->track->stsd.current->stream_type = (uint8_t)mov_buffer_r8(&mov->io) >> 2; /* stream type */
struct mov_sample_entry_t* entry = mov->track->stsd.current;
entry->object_type_indication = (uint8_t)mov_buffer_r8(&mov->io); /* objectTypeIndication */
entry->stream_type = (uint8_t)mov_buffer_r8(&mov->io) >> 2; /* stream type */
/*uint32_t bufferSizeDB = */mov_buffer_r24(&mov->io); /* buffer size db */
/*uint32_t max_rate = */mov_buffer_r32(&mov->io); /* max bit-rate */
/*uint32_t bit_rate = */mov_buffer_r32(&mov->io); /* avg bit-rate */
Expand All @@ -197,15 +200,16 @@ static int mp4_read_decoder_config_descriptor(struct mov_t* mov, int len)

static int mp4_write_decoder_config_descriptor(const struct mov_t* mov)
{
size_t size = 13 + (mov->track->extra_data_size > 0 ? mov->track->extra_data_size + 5 : 0);
const struct mov_sample_entry_t* entry = mov->track->stsd.current;
size_t size = 13 + (entry->extra_data_size > 0 ? entry->extra_data_size + 5 : 0);
mov_write_base_descr(mov, ISO_DecoderConfigDescrTag, size);
mov_buffer_w8(&mov->io, mov->track->stsd.current->object_type_indication);
mov_buffer_w8(&mov->io, 0x01/*reserved*/ | (mov->track->stsd.current->stream_type << 2));
mov_buffer_w8(&mov->io, entry->object_type_indication);
mov_buffer_w8(&mov->io, 0x01/*reserved*/ | (entry->stream_type << 2));
mov_buffer_w24(&mov->io, 0); /* buffer size db */
mov_buffer_w32(&mov->io, 88360); /* max bit-rate */
mov_buffer_w32(&mov->io, 88360); /* avg bit-rate */

if (mov->track->extra_data_size > 0)
if (entry->extra_data_size > 0)
mp4_write_decoder_specific_info(mov);

return size;
Expand Down Expand Up @@ -356,7 +360,8 @@ int mov_read_esds(struct mov_t* mov, const struct mov_box_t* box)
static size_t mp4_write_es_descriptor(const struct mov_t* mov)
{
size_t size = 3; // mp4_write_decoder_config_descriptor
size += 5 + 13 + (mov->track->extra_data_size > 0 ? mov->track->extra_data_size + 5 : 0); // mp4_write_decoder_config_descriptor
const struct mov_sample_entry_t* entry = mov->track->stsd.current;
size += 5 + 13 + (entry->extra_data_size > 0 ? entry->extra_data_size + 5 : 0); // mp4_write_decoder_config_descriptor
size += 5 + 1; // mp4_write_sl_config_descriptor

size += mov_write_base_descr(mov, ISO_ESDescrTag, size);
Expand Down
20 changes: 11 additions & 9 deletions libmov/source/mov-hvcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,24 +8,26 @@
int mov_read_hvcc(struct mov_t* mov, const struct mov_box_t* box)
{
struct mov_track_t* track = mov->track;
if (track->extra_data_size < box->size)
struct mov_sample_entry_t* entry = track->stsd.current;
if (entry->extra_data_size < box->size)
{
void* p = realloc(track->extra_data, (size_t)box->size);
void* p = realloc(entry->extra_data, (size_t)box->size);
if (NULL == p) return ENOMEM;
track->extra_data = p;
entry->extra_data = p;
}

mov_buffer_read(&mov->io, track->extra_data, (size_t)box->size);
track->extra_data_size = (size_t)box->size;
mov_buffer_read(&mov->io, entry->extra_data, (size_t)box->size);
entry->extra_data_size = (size_t)box->size;
return mov_buffer_error(&mov->io);
}

size_t mov_write_hvcc(const struct mov_t* mov)
{
const struct mov_track_t* track = mov->track;
mov_buffer_w32(&mov->io, track->extra_data_size + 8); /* size */
const struct mov_sample_entry_t* entry = track->stsd.current;
mov_buffer_w32(&mov->io, entry->extra_data_size + 8); /* size */
mov_buffer_write(&mov->io, "hvcC", 4);
if (track->extra_data_size > 0)
mov_buffer_write(&mov->io, track->extra_data, track->extra_data_size);
return track->extra_data_size + 8;
if (entry->extra_data_size > 0)
mov_buffer_write(&mov->io, entry->extra_data, entry->extra_data_size);
return entry->extra_data_size + 8;
}
4 changes: 2 additions & 2 deletions libmov/source/mov-internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#define MOV_SUBT MOV_TAG('s', 'u', 'b', 't') // ISO/IEC 14496-12:2015(E) 12.6 Subtitle media (p185)
#define MOV_FONT MOV_TAG('f', 'd', 's', 'm') // ISO/IEC 14496-12:2015(E) 12.7 Font media (p186)
#define MOV_CLCP MOV_TAG('c', 'l', 'c', 'p') // ClosedCaptionHandler
#define MOV_ALIS MOV_TAG('a', 'l', 'i', 's') // Apple QuickTime Macintosh alias

// https://developer.apple.com/library/content/documentation/General/Reference/HLSAuthoringSpec/Requirements.html#//apple_ref/doc/uid/TP40016596-CH2-SW1
// Video encoding requirements 1.10: Use ¡®avc1¡¯, ¡®hvc1¡¯, or ¡®dvh1¡¯ rather than ¡®avc3¡¯, ¡®hev1¡¯, or ¡®dvhe¡¯
Expand Down Expand Up @@ -145,8 +146,6 @@ struct mov_track_t
uint32_t tag; // MOV_H264/MOV_MP4A
uint32_t handler_type; // MOV_VIDEO/MOV_AUDIO
const char* handler_descr; // VideoHandler/SoundHandler/SubtitleHandler
uint8_t* extra_data; // H.264 sps/pps
size_t extra_data_size;

struct mov_tkhd_t tkhd;
struct mov_mdhd_t mdhd;
Expand Down Expand Up @@ -266,6 +265,7 @@ void mov_apply_stco(struct mov_track_t* track);
void mov_apply_elst(struct mov_track_t *track);
void mov_apply_stts(struct mov_track_t* track);
void mov_apply_ctts(struct mov_track_t* track);
void mov_apply_stss(struct mov_track_t* track);
void mov_apply_elst_tfdt(struct mov_track_t *track);

void mov_write_size(const struct mov_t* mov, uint64_t offset, size_t size);
Expand Down
28 changes: 13 additions & 15 deletions libmov/source/mov-reader.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,8 @@ static int mov_read_free(struct mov_t* mov, const struct mov_box_t* box)

//static struct mov_sample_entry_t* mov_track_stsd_find(struct mov_track_t* track, uint32_t sample_description_index)
//{
// size_t i;
// for (i = 0; i < track->stsd.entry_count; i++)
// {
// if (track->stsd.entries[i].data_reference_index == sample_description_index)
// return &track->stsd.entries[i];
// }
// if (sample_description_index > 0 && sample_description_index <= track->stsd.entry_count)
// return &track->stsd.entries[sample_description_index-1];
// return NULL;
//}

Expand Down Expand Up @@ -100,6 +96,7 @@ static int mov_read_trak(struct mov_t* mov, const struct mov_box_t* box)
mov_apply_elst(mov->track);
mov_apply_stts(mov->track);
mov_apply_ctts(mov->track);
mov_apply_stss(mov->track);

mov->track->tfdt_dts = mov->track->samples[mov->track->sample_count - 1].dts;
}
Expand Down Expand Up @@ -187,7 +184,7 @@ static struct mov_parse_t s_mov_parse_table[] = {
{ MOV_TAG('e', 's', 'd', 's'), MOV_NULL, mov_read_esds }, // ISO/IEC 14496-14:2003(E) mp4a/mp4v/mp4s
{ MOV_TAG('f', 'r', 'e', 'e'), MOV_NULL, mov_read_free },
{ MOV_TAG('f', 't', 'y', 'p'), MOV_ROOT, mov_read_ftyp },
{ MOV_TAG('h', 'd', 'l', 'r'), MOV_MDIA, mov_read_hdlr },
{ MOV_TAG('h', 'd', 'l', 'r'), MOV_MDIA, mov_read_hdlr }, // Apple QuickTime minf also has hdlr
{ MOV_TAG('h', 'v', 'c', 'C'), MOV_NULL, mov_read_hvcc }, // ISO/IEC 14496-15:2014 hvcC
{ MOV_TAG('l', 'e', 'v', 'a'), MOV_MVEX, mov_read_leva },
{ MOV_TAG('m', 'd', 'a', 't'), MOV_ROOT, mov_read_mdat },
Expand Down Expand Up @@ -272,9 +269,9 @@ int mov_reader_box(struct mov_t* mov, const struct mov_box_t* parent)
{
if (s_mov_parse_table[i].type == box.type)
{
assert(MOV_NULL == s_mov_parse_table[i].parent
|| s_mov_parse_table[i].parent == parent->type);
parse = s_mov_parse_table[i].parse;
// Apple QuickTime minf also has hdlr
if(!s_mov_parse_table[i].parent || s_mov_parse_table[i].parent == parent->type)
parse = s_mov_parse_table[i].parse;
}
}

Expand Down Expand Up @@ -415,7 +412,8 @@ int mov_reader_read(struct mov_reader_t* reader, void* buffer, size_t bytes, mov
}

track->sample_offset++; //mark as read
onread(param, track->tkhd.track_ID, buffer, sample->bytes, sample->pts * 1000 / track->mdhd.timescale, sample->dts * 1000 / track->mdhd.timescale);
assert(sample->sample_description_index > 0);
onread(param, track->tkhd.track_ID, /*sample->sample_description_index-1,*/ buffer, sample->bytes, sample->pts * 1000 / track->mdhd.timescale, sample->dts * 1000 / track->mdhd.timescale, sample->flags);
return 1;
}

Expand Down Expand Up @@ -463,16 +461,16 @@ int mov_reader_getinfo(struct mov_reader_t* reader, struct mov_reader_trackinfo_
switch (track->handler_type)
{
case MOV_VIDEO:
if(ontrack->onvideo) ontrack->onvideo(param, track->tkhd.track_ID, entry->object_type_indication, entry->u.visual.width, entry->u.visual.height, track->extra_data, track->extra_data_size);
if(ontrack->onvideo) ontrack->onvideo(param, track->tkhd.track_ID, entry->object_type_indication, entry->u.visual.width, entry->u.visual.height, entry->extra_data, entry->extra_data_size);
break;

case MOV_AUDIO:
if (ontrack->onaudio) ontrack->onaudio(param, track->tkhd.track_ID, entry->object_type_indication, entry->u.audio.channelcount, entry->u.audio.samplesize, entry->u.audio.samplerate >> 16, track->extra_data, track->extra_data_size);
if (ontrack->onaudio) ontrack->onaudio(param, track->tkhd.track_ID, entry->object_type_indication, entry->u.audio.channelcount, entry->u.audio.samplesize, entry->u.audio.samplerate >> 16, entry->extra_data, entry->extra_data_size);
break;

case MOV_SUBT:
case MOV_TEXT:
if (ontrack->onsubtitle) ontrack->onsubtitle(param, track->tkhd.track_ID, MOV_OBJECT_TEXT, track->extra_data, track->extra_data_size);
if (ontrack->onsubtitle) ontrack->onsubtitle(param, track->tkhd.track_ID, MOV_OBJECT_TEXT, entry->extra_data, entry->extra_data_size);
break;

default:
Expand Down Expand Up @@ -500,7 +498,7 @@ static int mov_stss_seek(struct mov_track_t* track, int64_t *timestamp)
idx = mid = start = 0;
end = track->stbl.stss_count;
assert(track->stbl.stss_count > 0);
clock = *timestamp * track->mdhd.timescale / 1000; // mvhd timecale
clock = *timestamp * track->mdhd.timescale / 1000; // mvhd timescale

while (start < end)
{
Expand Down
Loading

0 comments on commit 6ae6ece

Please sign in to comment.