diff options
-rw-r--r-- | gst/qtdemux/qtdemux.c | 406 | ||||
-rw-r--r-- | gst/qtdemux/qtdemux.h | 3 |
2 files changed, 304 insertions, 105 deletions
diff --git a/gst/qtdemux/qtdemux.c b/gst/qtdemux/qtdemux.c index 8dc2960c..2ba7d547 100644 --- a/gst/qtdemux/qtdemux.c +++ b/gst/qtdemux/qtdemux.c @@ -21,6 +21,16 @@ #include "qtdemux.h" #include <string.h> +#include <zlib.h> + +#define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a)) +#define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a)) +#define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a)) +#define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0) +#define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0) +#define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a)) + +#define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4)) typedef struct _QtNode QtNode; typedef struct _QtNodeType QtNodeType; @@ -57,17 +67,26 @@ struct _QtDemuxStream { int timescale; int sample_index; + + int width; + int height; + double rate; + int n_channels; }; enum QtDemuxState { QTDEMUX_STATE_NULL, QTDEMUX_STATE_HEADER, + QTDEMUX_STATE_HEADER_SEEKING, QTDEMUX_STATE_SEEKING, QTDEMUX_STATE_MOVIE, QTDEMUX_STATE_SEEKING_EOS, QTDEMUX_STATE_EOS, }; +static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc); +static GNode *qtdemux_tree_get_sibling_by_type(GNode *node, guint32 fourcc); + static GstElementDetails gst_qtdemux_details = { @@ -301,24 +320,32 @@ static void gst_qtdemux_loop_header (GstElement *element) int size; int ret; - - GST_DEBUG(0,"loop at position %d",(int)gst_bytestream_tell(qtdemux->bs)); + /* FIXME _tell gets the offset wrong */ + //cur_offset = gst_bytestream_tell(qtdemux->bs); + + cur_offset = qtdemux->offset; + GST_DEBUG(0,"loop at position %d",cur_offset); switch(qtdemux->state){ case QTDEMUX_STATE_HEADER: { - ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16); - if(ret<16){ - gst_qtdemux_handle_sink_event(qtdemux); - return; - } + do{ + ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 16); + if(ret<16){ + if(!gst_qtdemux_handle_sink_event(qtdemux)){ + return; + } + }else{ + break; + } + }while(1); length = GUINT32_FROM_BE(*(guint32 *)data); GST_DEBUG(0,"length %08x",length); fourcc = GUINT32_FROM_LE(*(guint32 *)(data+4)); GST_DEBUG(0,"fourcc " GST_FOURCC_FORMAT, GST_FOURCC_ARGS(fourcc)); if(length==0){ - length = gst_bytestream_length(qtdemux->bs) - gst_bytestream_tell(qtdemux->bs); + length = gst_bytestream_length(qtdemux->bs) - cur_offset; } if(length==1){ guint32 length1, length2; @@ -333,50 +360,42 @@ static void gst_qtdemux_loop_header (GstElement *element) switch(fourcc){ case GST_MAKE_FOURCC('m','d','a','t'): - { - int ret; - int pos; - - pos = gst_bytestream_tell(qtdemux->bs); - ret = gst_bytestream_seek(qtdemux->bs, pos + length, GST_SEEK_METHOD_SET); - GST_DEBUG(0,"seek returned %d",ret); - return; - } + case GST_MAKE_FOURCC('f','r','e','e'): + case GST_MAKE_FOURCC('w','i','d','e'): + break; case GST_MAKE_FOURCC('m','o','o','v'): { GstBuffer *moov; - guint32 n_read; - n_read = gst_bytestream_read(qtdemux->bs, &moov, length); - if(n_read<length){ - /* FIXME */ - g_warning("need to handle event\n"); - } + do{ + ret = gst_bytestream_read(qtdemux->bs, &moov, length); + if(ret < length){ + GST_DEBUG(0,"read failed (%d < %d)",ret,length); + if(!gst_qtdemux_handle_sink_event(qtdemux)){ + return; + } + }else{ + break; + } + }while(1); + qtdemux_parse_moov(qtdemux, GST_BUFFER_DATA(moov), length); if(0)qtdemux_node_dump(qtdemux, qtdemux->moov_node); qtdemux_parse_tree(qtdemux); qtdemux->state = QTDEMUX_STATE_MOVIE; break; } - case GST_MAKE_FOURCC('f','r','e','e'): - { - gst_bytestream_flush(qtdemux->bs, length); - break; - } - case GST_MAKE_FOURCC('w','i','d','e'): - { - gst_bytestream_flush(qtdemux->bs, length); - break; - } default: { - g_print("unknown %08x '" GST_FOURCC_FORMAT "' at %" G_GUINT64_FORMAT "\n", - GST_MAKE_FOURCC('1','2','3','4'), - GST_FOURCC_ARGS(GST_MAKE_FOURCC('1','2','3','4')),gst_bytestream_tell(qtdemux->bs)); - gst_bytestream_flush(qtdemux->bs, length); + g_print("unknown %08x '" GST_FOURCC_FORMAT "' at %d\n", + fourcc, GST_FOURCC_ARGS(fourcc), cur_offset); break; } } + ret = gst_bytestream_seek(qtdemux->bs, cur_offset + length, + GST_SEEK_METHOD_SET); + qtdemux->offset = cur_offset + length; + GST_DEBUG(0,"seek returned %d\n",ret); break; } case QTDEMUX_STATE_SEEKING_EOS: @@ -385,7 +404,6 @@ static void gst_qtdemux_loop_header (GstElement *element) do{ ret = gst_bytestream_peek_bytes(qtdemux->bs, &data, 1); - g_print("peek_bytes returned %d after EOS seek\n",ret); if(ret<1){ if(!gst_qtdemux_handle_sink_event(qtdemux)){ return; @@ -437,23 +455,14 @@ static void gst_qtdemux_loop_header (GstElement *element) offset = stream->samples[stream->sample_index].offset; size = stream->samples[stream->sample_index].size; + GST_DEBUG(0,"pushing from stream %d, sample_index=%d offset=%d size=%d", + index, stream->sample_index, offset, size); + cur_offset = gst_bytestream_tell(qtdemux->bs); if(offset != cur_offset){ GST_DEBUG(0,"seeking to offset %d",offset); ret = gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET); GST_DEBUG(0,"seek returned %d",ret); -#if 0 - if(!gst_bytestream_seek(qtdemux->bs, offset, GST_SEEK_METHOD_SET)){ - GstEvent *event; - guint32 remaining; - - g_print("seek failed\n"); - gst_bytestream_get_status(qtdemux->bs, &remaining, &event); - - gst_pad_push(stream->pad, GST_BUFFER(event)); - return; - } -#endif return; } @@ -485,6 +494,60 @@ static void gst_qtdemux_loop_header (GstElement *element) } +static GstCaps *gst_qtdemux_src_getcaps(GstPad *pad, GstCaps *caps) +{ + GstQTDemux *qtdemux; + QtDemuxStream *stream; + int i; + + GST_DEBUG(0,"gst_qtdemux_src_getcaps"); + + qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad)); + + g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), NULL); + + GST_DEBUG(0, "looking for pad %p in qtdemux %p", pad, qtdemux); + GST_DEBUG(0, "n_streams is %d", qtdemux->n_streams); + for(i=0;i<qtdemux->n_streams;i++){ + stream = qtdemux->streams[i]; + if(stream->pad == pad){ + return stream->caps; + } + } + + GST_DEBUG(0,"Couldn't find stream cooresponding to pad\n"); + + return NULL; +} + +static GstPadLinkReturn +gst_qtdemux_src_link(GstPad *pad, GstCaps *caps) +{ + GstQTDemux *qtdemux; + QtDemuxStream *stream; + int i; + + GST_DEBUG(0,"gst_qtdemux_src_link"); + + qtdemux = GST_QTDEMUX(gst_pad_get_parent(pad)); + + GST_DEBUG(0, "looking for pad %p in qtdemux %p", pad, qtdemux); + g_return_val_if_fail(GST_IS_QTDEMUX(qtdemux), GST_PAD_LINK_REFUSED); + + GST_DEBUG(0, "n_streams is %d", qtdemux->n_streams); + for(i=0;i<qtdemux->n_streams;i++){ + stream = qtdemux->streams[i]; + GST_DEBUG(0, "pad[%d] is %p", i, stream->pad); + if(stream->pad == pad){ + return GST_PAD_LINK_OK; + } + } + + GST_DEBUG(0,"Couldn't find stream cooresponding to pad\n"); + + return GST_PAD_LINK_REFUSED; +} + void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream) { if(stream->subtype == GST_MAKE_FOURCC('v','i','d','e')){ @@ -493,12 +556,10 @@ void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream) qtdemux->n_video_streams)); if(stream->caps){ if(gst_caps_has_property(stream->caps,"width")){ - /* FIXME */ - gst_caps_set(stream->caps,"width",GST_PROPS_INT(100)); + gst_caps_set(stream->caps,"width",GST_PROPS_INT(stream->width)); } if(gst_caps_has_property(stream->caps,"height")){ - /* FIXME */ - gst_caps_set(stream->caps,"height",GST_PROPS_INT(100)); + gst_caps_set(stream->caps,"height",GST_PROPS_INT(stream->height)); } } qtdemux->n_video_streams++; @@ -508,25 +569,31 @@ void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream) qtdemux->n_audio_streams)); if(stream->caps){ if(gst_caps_has_property(stream->caps,"rate")){ - /* FIXME */ - gst_caps_set(stream->caps,"rate",GST_PROPS_INT(44100)); + gst_caps_set(stream->caps,"rate",GST_PROPS_INT((int)stream->rate)); } if(gst_caps_has_property(stream->caps,"channels")){ - /* FIXME */ - gst_caps_set(stream->caps,"channels",GST_PROPS_INT(2)); + gst_caps_set(stream->caps,"channels",GST_PROPS_INT(stream->n_channels)); } } - - g_print("setting caps to %s\n",gst_caps_to_string(stream->caps)); qtdemux->n_audio_streams++; } + + gst_pad_set_getcaps_function(stream->pad, gst_qtdemux_src_getcaps); + gst_pad_set_link_function(stream->pad, gst_qtdemux_src_link); + + qtdemux->streams[qtdemux->n_streams] = stream; + qtdemux->n_streams++; + GST_DEBUG(0, "n_streams is now %d", qtdemux->n_streams); + + GST_DEBUG(0, "adding pad %p to qtdemux %p", stream->pad, qtdemux); gst_element_add_pad(GST_ELEMENT (qtdemux), stream->pad); + + /* Note: we need to have everything set up before calling try_set_caps */ if(stream->caps){ + g_print("setting caps to %s\n",gst_caps_to_string(stream->caps)); + gst_pad_try_set_caps(stream->pad, stream->caps); } - - qtdemux->streams[qtdemux->n_streams] = stream; - qtdemux->n_streams++; } @@ -569,6 +636,9 @@ void gst_qtdemux_add_stream(GstQTDemux *qtdemux, QtDemuxStream *stream) #define FOURCC_vide GST_MAKE_FOURCC('v','i','d','e') #define FOURCC_soun GST_MAKE_FOURCC('s','o','u','n') #define FOURCC_co64 GST_MAKE_FOURCC('c','o','6','4') +#define FOURCC_cmov GST_MAKE_FOURCC('c','m','o','v') +#define FOURCC_dcom GST_MAKE_FOURCC('d','c','o','m') +#define FOURCC_cmvd GST_MAKE_FOURCC('c','m','v','d') static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth); @@ -585,6 +655,8 @@ static void qtdemux_dump_stsc(GstQTDemux *qtdemux, void *buffer, int depth); static void qtdemux_dump_stsz(GstQTDemux *qtdemux, void *buffer, int depth); static void qtdemux_dump_stco(GstQTDemux *qtdemux, void *buffer, int depth); static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth); +static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth); +static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth); QtNodeType qt_node_types[] = { { FOURCC_moov, "movie", QT_CONTAINER, }, @@ -637,19 +709,96 @@ QtNodeType qt_node_types[] = { { FOURCC_co64, "64-bit chunk offset", 0, qtdemux_dump_co64 }, { FOURCC_vide, "video media", 0 }, + { FOURCC_cmov, "compressed movie", QT_CONTAINER }, + { FOURCC_dcom, "compressed data", 0, + qtdemux_dump_dcom }, + { FOURCC_cmvd, "compressed movie data", 0, + qtdemux_dump_cmvd }, { 0, "unknown", 0 }, }; static int n_qt_node_types = sizeof(qt_node_types)/sizeof(qt_node_types[0]); +static void *qtdemux_zalloc(void *opaque, unsigned int items, unsigned int size) +{ + return g_malloc(items*size); +} + +static void qtdemux_zfree(void *opaque, void *addr) +{ + g_free(addr); +} + +static void *qtdemux_inflate(void *z_buffer, int z_length, int length) +{ + void *buffer; + z_stream *z; + int ret; + + z = g_new0(z_stream, 1); + z->zalloc = qtdemux_zalloc; + z->zfree = qtdemux_zfree; + z->opaque = NULL; + + z->next_in = z_buffer; + z->avail_in = z_length; + + buffer = g_malloc(length); + ret = inflateInit(z); + while(z->avail_in > 0){ + if(z->avail_out == 0){ + length += 1024; + buffer = realloc(buffer, length); + z->next_out = buffer + z->total_out; + z->avail_out = 1024; + } + ret = inflate(z,Z_SYNC_FLUSH); + if(ret != Z_OK)break; + } + if(ret != Z_STREAM_END){ + g_warning("inflate() returned %d\n",ret); + } + + g_free(z); + return buffer; +} static void qtdemux_parse_moov(GstQTDemux *qtdemux, void *buffer, int length) { + GNode *cmov; qtdemux->moov_node = g_node_new(buffer); qtdemux_parse(qtdemux, qtdemux->moov_node, buffer, length); + cmov = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_cmov); + if(cmov){ + GNode *dcom; + GNode *cmvd; + + dcom = qtdemux_tree_get_child_by_type(cmov, FOURCC_dcom); + cmvd = qtdemux_tree_get_child_by_type(cmov, FOURCC_cmvd); + + if(QTDEMUX_FOURCC_GET(dcom->data+8) == GST_MAKE_FOURCC('z','l','i','b')){ + int uncompressed_length; + int compressed_length; + void *buf; + + uncompressed_length = QTDEMUX_GUINT32_GET(cmvd->data+8); + compressed_length = QTDEMUX_GUINT32_GET(cmvd->data+4) - 12; + g_print("length = %d\n",uncompressed_length); + + buf = qtdemux_inflate(cmvd->data + 12, compressed_length, + uncompressed_length); + + qtdemux->moov_node_compressed = qtdemux->moov_node; + qtdemux->moov_node = g_node_new(buf); + + qtdemux_parse(qtdemux, qtdemux->moov_node, buf, uncompressed_length); + }else{ + g_print("unknown header compression type\n"); + } + } } static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int length) @@ -661,8 +810,8 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le //g_print("qtdemux_parse %p %d\n",buffer, length); - node_length = GUINT32_FROM_BE(*(guint32 *)buffer); - fourcc = GUINT32_FROM_LE(*(guint32 *)(buffer+4)); + node_length = QTDEMUX_GUINT32_GET(buffer); + fourcc = QTDEMUX_FOURCC_GET(buffer+4); type = qtdemux_type_get(fourcc); @@ -682,7 +831,7 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le /* FIXME: get annoyed */ g_print("buffer overrun\n"); } - len = GUINT32_FROM_BE(*(guint32 *)buf); + len = QTDEMUX_GUINT32_GET(buf); child = g_node_new(buf); g_node_append(node, child); @@ -691,8 +840,35 @@ static void qtdemux_parse(GstQTDemux *qtdemux, GNode *node, void *buffer, int le buf += len; } }else{ - //g_print("not container\n"); +#if 0 + if(fourcc == FOURCC_cmvd){ + int uncompressed_length; + void *buf; + + uncompressed_length = QTDEMUX_GUINT32_GET(buffer+8); + g_print("length = %d\n",uncompressed_length); + + buf = qtdemux_inflate(buffer + 12, node_length-12, uncompressed_length); + + end = buf + uncompressed_length; + while(buf < end){ + GNode *child; + guint32 len; + + if(buf + 8 >= end){ + /* FIXME: get annoyed */ + g_print("buffer overrun\n"); + } + len = QTDEMUX_GUINT32_GET(buf); + child = g_node_new(buf); + g_node_append(node, child); + qtdemux_parse(qtdemux, child, buf, len); + + buf += len; + } + } +#endif } } @@ -738,15 +914,6 @@ static void qtdemux_node_dump(GstQTDemux *qtdemux, GNode *node) qtdemux_node_dump_foreach, qtdemux); } -#define QTDEMUX_GUINT32_GET(a) GUINT32_FROM_BE(*(guint32 *)(a)) -#define QTDEMUX_GUINT16_GET(a) GUINT16_FROM_BE(*(guint16 *)(a)) -#define QTDEMUX_GUINT8_GET(a) (*(guint8 *)(a)) -#define QTDEMUX_FP32_GET(a) (GUINT32_FROM_BE(*(guint16 *)(a))/65536.0) -#define QTDEMUX_FP16_GET(a) (GUINT16_FROM_BE(*(guint16 *)(a))/256.0) -#define QTDEMUX_FOURCC_GET(a) GUINT32_FROM_LE(*(guint32 *)(a)) - -#define QTDEMUX_GUINT64_GET(a) ((((guint64)QTDEMUX_GUINT32_GET(a))<<32)|QTDEMUX_GUINT32_GET(((void *)a)+4)) - static void qtdemux_dump_mvhd(GstQTDemux *qtdemux, void *buffer, int depth) { g_print("%*s version/flags: %08x\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8)); @@ -993,6 +1160,17 @@ static void qtdemux_dump_co64(GstQTDemux *qtdemux, void *buffer, int depth) } } +static void qtdemux_dump_dcom(GstQTDemux *qtdemux, void *buffer, int depth) +{ + g_print("%*s compression type: " GST_FOURCC_FORMAT "\n", depth, "", + GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(buffer+8))); +} + +static void qtdemux_dump_cmvd(GstQTDemux *qtdemux, void *buffer, int depth) +{ + g_print("%*s length: %d\n", depth, "", QTDEMUX_GUINT32_GET(buffer+8)); +} + static GNode *qtdemux_tree_get_child_by_type(GNode *node, guint32 fourcc) { @@ -1038,6 +1216,10 @@ static void qtdemux_parse_tree(GstQTDemux *qtdemux) GNode *trak; mvhd = qtdemux_tree_get_child_by_type(qtdemux->moov_node, FOURCC_mvhd); + if(mvhd==NULL){ + g_print("No mvhd node found.\n"); + return; + } qtdemux->timescale = QTDEMUX_GUINT32_GET(mvhd->data + 20); qtdemux->duration = QTDEMUX_GUINT32_GET(mvhd->data + 24); @@ -1085,20 +1267,13 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak) /* track duration? */ - //g_print("track duration: %u\n", QTDEMUX_GUINT32_GET(buffer+28)); - - g_print("track width: %g\n", QTDEMUX_FP32_GET(tkhd->data+84)); - g_print("track height: %g\n", QTDEMUX_FP32_GET(tkhd->data+88)); - mdia = qtdemux_tree_get_child_by_type(trak, FOURCC_mdia); g_assert(mdia); mdhd = qtdemux_tree_get_child_by_type(mdia, FOURCC_mdhd); g_assert(mdhd); - g_print("track time scale: %d\n", QTDEMUX_GUINT32_GET(mdhd->data+20)); stream->timescale = QTDEMUX_GUINT32_GET(mdhd->data+20); - //g_print("track height: %g\n", QTDEMUX_FP32_GET(mdhd->data+88)); hdlr = qtdemux_tree_get_child_by_type(mdia, FOURCC_hdlr); g_assert(hdlr); @@ -1124,34 +1299,38 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak) g_print("st type: " GST_FOURCC_FORMAT "\n", GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+offset+4))); - g_print("width: %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+32)); - g_print("height: %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+34)); - - //g_print("data size: %u\n", QTDEMUX_GUINT32_GET(stsd->data+offset+44)); - //g_print("frame count: %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48)); + stream->width = QTDEMUX_GUINT16_GET(stsd->data+offset+32); + stream->height = QTDEMUX_GUINT16_GET(stsd->data+offset+34); - //g_print("compressor: %*s\n", QTDEMUX_GUINT8_GET(stsd->data+offset+49), (char *)(stsd->data+offset+51)); + g_print("frame count: %u\n", QTDEMUX_GUINT16_GET(stsd->data+offset+48)); stream->caps = qtdemux_video_caps(qtdemux, QTDEMUX_FOURCC_GET(stsd->data+offset+4)); g_print("caps %s\n",gst_caps_to_string(stream->caps)); }else if(stream->subtype == FOURCC_soun){ + int version; + g_print("st type: " GST_FOURCC_FORMAT "\n", GST_FOURCC_ARGS(QTDEMUX_FOURCC_GET(stsd->data+16+4))); offset = 32; g_print("version/rev: %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset)); + version = QTDEMUX_GUINT32_GET(stsd->data+offset); g_print("vendor: %08x\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 4)); g_print("n_channels: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 8)); + stream->n_channels = QTDEMUX_GUINT16_GET(stsd->data+offset + 8); g_print("sample_size: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 10)); g_print("compression_id: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 12)); g_print("packet size: %d\n", QTDEMUX_GUINT16_GET(stsd->data+offset + 14)); - g_print("sample rate: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 16)); - - g_print("samples/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 20)); - g_print("bytes/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 24)); - g_print("bytes/frame: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 28)); - g_print("bytes/sample: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 32)); + g_print("sample rate: %g\n", QTDEMUX_FP32_GET(stsd->data+offset + 16)); + stream->rate = QTDEMUX_FP32_GET(stsd->data+offset + 16); + + if(version == 0x00010000){ + g_print("samples/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 20)); + g_print("bytes/packet: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 24)); + g_print("bytes/frame: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 28)); + g_print("bytes/sample: %d\n", QTDEMUX_GUINT32_GET(stsd->data+offset + 32)); + } stream->caps = qtdemux_audio_caps(qtdemux, QTDEMUX_FOURCC_GET(stsd->data+16+4)); @@ -1161,6 +1340,11 @@ static void qtdemux_parse_trak(GstQTDemux *qtdemux, GNode *trak) return; } + if(stream->caps){ + gst_caps_ref(stream->caps); + gst_caps_sink(stream->caps); + } + /* sample to chunk */ stsc = qtdemux_tree_get_child_by_type(stbl, FOURCC_stsc); g_assert(stsc); @@ -1236,6 +1420,8 @@ done: } } }else{ + int sample_width; + g_print("treating chunks as samples\n"); /* treat chunks as samples */ @@ -1248,6 +1434,8 @@ done: samples = g_malloc(sizeof(QtDemuxSample)*n_samples); stream->samples = samples; + sample_width = QTDEMUX_GUINT16_GET(stsd->data+offset + 10) / 8; + n_samples_per_chunk = QTDEMUX_GUINT32_GET(stsc->data+12); offset = 16; sample_index = 0; @@ -1272,7 +1460,7 @@ done: } samples[j].chunk = j; samples[j].offset = chunk_offset; - samples[j].size = samples_per_chunk; /* FIXME */ + samples[j].size = samples_per_chunk * stream->n_channels * sample_width; samples[j].sample_index = sample_index; sample_index += samples_per_chunk; if(j>=n_samples)goto done2; @@ -1302,13 +1490,14 @@ done2: } } - +#if 0 for(i=0;i<n_samples;i++){ g_print("%d: %d %d %d %d %" G_GUINT64_FORMAT "\n",i, samples[i].sample_index,samples[i].chunk, samples[i].offset, samples[i].size, samples[i].timestamp); if(i>10)break; } +#endif gst_qtdemux_add_stream(qtdemux,stream); } @@ -1322,10 +1511,10 @@ static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc) return GST_CAPS_NEW("jpeg_caps","video/jpeg",NULL); case GST_MAKE_FOURCC('m','j','p','a'): /* Motion-JPEG (format A) */ - return GST_CAPS_NEW("mjpa_caps","video/x-mjpeg",NULL); + return GST_CAPS_NEW("mjpa_caps","video/jpeg",NULL); case GST_MAKE_FOURCC('m','j','p','b'): /* Motion-JPEG (format B) */ - return GST_CAPS_NEW("mjpa_caps","video/x-mjpeg",NULL); + return GST_CAPS_NEW("mjpa_caps","video/jpeg",NULL); case GST_MAKE_FOURCC('S','V','Q','3'): return GST_CAPS_NEW("SVQ3_caps","video/x-svq", "svqversion", GST_PROPS_INT(3),NULL); @@ -1350,17 +1539,24 @@ static GstCaps *qtdemux_video_caps(GstQTDemux *qtdemux, guint32 fourcc) return GST_CAPS_NEW("mpeg_caps","video/mpeg",NULL); case GST_MAKE_FOURCC('g','i','f',' '): return GST_CAPS_NEW("gif__caps","image/gif",NULL); + case GST_MAKE_FOURCC('h','2','6','3'): + /* H.263 */ + /* ffmpeg uses the height/width props, don't know why */ + return GST_CAPS_NEW("h263_caps","video/h263", + "width",GST_PROPS_INT_RANGE(1,G_MAXINT), + "height",GST_PROPS_INT_RANGE(1,G_MAXINT)); case GST_MAKE_FOURCC('m','p','4','v'): /* MPEG-4 */ - return NULL; - //return GST_CAPS_NEW("mp4v_caps", "video/mpeg",NULL); + return GST_CAPS_NEW("mp4v_caps", "video/mpeg", + "mpegversion",GST_PROPS_INT(4)); + case GST_MAKE_FOURCC('3','I','V','1'): + return GST_CAPS_NEW("3IV1_caps", "video/3ivx",NULL); case GST_MAKE_FOURCC('r','p','z','a'): case GST_MAKE_FOURCC('c','v','i','d'): /* Cinepak */ case GST_MAKE_FOURCC('r','l','e',' '): case GST_MAKE_FOURCC('s','m','c',' '): case GST_MAKE_FOURCC('k','p','c','d'): - case GST_MAKE_FOURCC('3','I','V','1'): default: g_print("Don't know how to convert fourcc '" GST_FOURCC_FORMAT "' to caps\n", GST_FOURCC_ARGS(fourcc)); @@ -1467,16 +1663,16 @@ static GstCaps *qtdemux_audio_caps(GstQTDemux *qtdemux, guint32 fourcc) /* DV audio */ case GST_MAKE_FOURCC('q','t','v','r'): /* ? */ - case GST_MAKE_FOURCC('Q','D','M','C'): - /* QDesign music */ case GST_MAKE_FOURCC('Q','D','M','2'): /* QDesign music version 2 (no constant) */ + case GST_MAKE_FOURCC('Q','D','M','C'): + /* QDesign music */ case GST_MAKE_FOURCC('M','A','C','3'): /* MACE 3:1 */ case GST_MAKE_FOURCC('M','A','C','6'): /* MACE 6:1 */ case GST_MAKE_FOURCC('i','m','a','4'): - /* ? */ + /* IMA 4:1 */ case GST_MAKE_FOURCC('Q','c','l','p'): /* QUALCOMM PureVoice */ default: diff --git a/gst/qtdemux/qtdemux.h b/gst/qtdemux/qtdemux.h index 53af27b7..108faab1 100644 --- a/gst/qtdemux/qtdemux.h +++ b/gst/qtdemux/qtdemux.h @@ -60,12 +60,15 @@ struct _GstQTDemux { GstByteStream *bs; GNode *moov_node; + GNode *moov_node_compressed; guint32 timescale; guint32 duration; int state; + int offset; + /* track stuff */ }; |