winlin

update readme

@@ -123,7 +123,6 @@ Please select your language: @@ -123,7 +123,6 @@ Please select your language:
123 * [SRS 2.0 English][v2_EN_Home] 123 * [SRS 2.0 English][v2_EN_Home]
124 * [SRS 2.0 Chinese][v2_CN_Home] 124 * [SRS 2.0 Chinese][v2_CN_Home]
125 125
126 -<<<<<<< HEAD  
127 ### SRS 3.0 wiki 126 ### SRS 3.0 wiki
128 127
129 Please select your language: 128 Please select your language:
@@ -182,6 +181,8 @@ Please select your language: @@ -182,6 +181,8 @@ Please select your language:
182 - [ ] Support MPEG-DASH, the future streaming protocol, read [#299][bug #299]. 181 - [ ] Support MPEG-DASH, the future streaming protocol, read [#299][bug #299].
183 - [ ] Support HLS+, please read [#466][bug #466] and [#468][bug #468]. 182 - [ ] Support HLS+, please read [#466][bug #466] and [#468][bug #468].
184 183
  184 +### Change Logs
  185 +
185 ### V3 changes 186 ### V3 changes
186 187
187 * v3.0, 2017-01-19, for [#742][bug #742] refine source, meta and origin hub. 3.0.16 188 * v3.0, 2017-01-19, for [#742][bug #742] refine source, meta and origin hub. 3.0.16
@@ -250,6 +250,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -250,6 +250,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
250 #define ERROR_MP4_BOX_ILLEGAL_BRAND 3074 250 #define ERROR_MP4_BOX_ILLEGAL_BRAND 3074
251 #define ERROR_MP4_NOT_NON_SEEKABLE 3075 251 #define ERROR_MP4_NOT_NON_SEEKABLE 3075
252 #define ERROR_MP4_ESDS_SL_Config 3076 252 #define ERROR_MP4_ESDS_SL_Config 3076
  253 +#define ERROR_MP4_ILLEGAL_MOOV 3077
253 254
254 /////////////////////////////////////////////////////// 255 ///////////////////////////////////////////////////////
255 // HTTP/StreamCaster/KAFKA protocol error. 256 // HTTP/StreamCaster/KAFKA protocol error.
@@ -141,15 +141,17 @@ extern ISrsThreadContext* _srs_context; @@ -141,15 +141,17 @@ extern ISrsThreadContext* _srs_context;
141 #define srs_trace(msg, ...) _srs_log->trace(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__) 141 #define srs_trace(msg, ...) _srs_log->trace(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
142 #define srs_warn(msg, ...) _srs_log->warn(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__) 142 #define srs_warn(msg, ...) _srs_log->warn(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
143 #define srs_error(msg, ...) _srs_log->error(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__) 143 #define srs_error(msg, ...) _srs_log->error(NULL, _srs_context->get_id(), msg, ##__VA_ARGS__)
  144 +#endif
144 // use __FUNCTION__ to print c method 145 // use __FUNCTION__ to print c method
145 -#elif 0 146 +#if 0
146 #define srs_verbose(msg, ...) _srs_log->verbose(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 147 #define srs_verbose(msg, ...) _srs_log->verbose(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
147 #define srs_info(msg, ...) _srs_log->info(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 148 #define srs_info(msg, ...) _srs_log->info(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
148 #define srs_trace(msg, ...) _srs_log->trace(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 149 #define srs_trace(msg, ...) _srs_log->trace(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
149 #define srs_warn(msg, ...) _srs_log->warn(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 150 #define srs_warn(msg, ...) _srs_log->warn(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
150 #define srs_error(msg, ...) _srs_log->error(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 151 #define srs_error(msg, ...) _srs_log->error(__FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
  152 +#endif
151 // use __PRETTY_FUNCTION__ to print c++ class:method 153 // use __PRETTY_FUNCTION__ to print c++ class:method
152 -#else 154 +#if 0
153 #define srs_verbose(msg, ...) _srs_log->verbose(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 155 #define srs_verbose(msg, ...) _srs_log->verbose(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
154 #define srs_info(msg, ...) _srs_log->info(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 156 #define srs_info(msg, ...) _srs_log->info(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
155 #define srs_trace(msg, ...) _srs_log->trace(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__) 157 #define srs_trace(msg, ...) _srs_log->trace(__PRETTY_FUNCTION__, _srs_context->get_id(), msg, ##__VA_ARGS__)
@@ -121,6 +121,19 @@ bool SrsMp4Box::is_mdat() @@ -121,6 +121,19 @@ bool SrsMp4Box::is_mdat()
121 return type == SrsMp4BoxTypeMDAT; 121 return type == SrsMp4BoxTypeMDAT;
122 } 122 }
123 123
  124 +SrsMp4Box* SrsMp4Box::get(SrsMp4BoxType bt)
  125 +{
  126 + vector<SrsMp4Box*>::iterator it;
  127 + for (it = boxes.begin(); it != boxes.end(); ++it) {
  128 + SrsMp4Box* box = *it;
  129 + if (box->type == bt) {
  130 + return box;
  131 + }
  132 + }
  133 +
  134 + return NULL;
  135 +}
  136 +
124 int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox) 137 int SrsMp4Box::discovery(SrsBuffer* buf, SrsMp4Box** ppbox)
125 { 138 {
126 *ppbox = NULL; 139 *ppbox = NULL;
@@ -625,6 +638,40 @@ SrsMp4MovieBox::~SrsMp4MovieBox() @@ -625,6 +638,40 @@ SrsMp4MovieBox::~SrsMp4MovieBox()
625 { 638 {
626 } 639 }
627 640
  641 +SrsMp4MovieHeaderBox* SrsMp4MovieBox::mvhd()
  642 +{
  643 + SrsMp4Box* box = get(SrsMp4BoxTypeMVHD);
  644 + return dynamic_cast<SrsMp4MovieHeaderBox*>(box);
  645 +}
  646 +
  647 +SrsMp4TrackBox* SrsMp4MovieBox::video()
  648 +{
  649 + for (int i = 0; i < boxes.size(); i++) {
  650 + SrsMp4Box* box = boxes.at(i);
  651 + if (box->type == SrsMp4BoxTypeTRAK) {
  652 + SrsMp4TrackBox* trak = dynamic_cast<SrsMp4TrackBox*>(box);
  653 + if ((trak->track_type() & SrsMp4TrackTypeVideo) == SrsMp4TrackTypeVideo) {
  654 + return trak;
  655 + }
  656 + }
  657 + }
  658 + return NULL;
  659 +}
  660 +
  661 +SrsMp4TrackBox* SrsMp4MovieBox::audio()
  662 +{
  663 + for (int i = 0; i < boxes.size(); i++) {
  664 + SrsMp4Box* box = boxes.at(i);
  665 + if (box->type == SrsMp4BoxTypeTRAK) {
  666 + SrsMp4TrackBox* trak = dynamic_cast<SrsMp4TrackBox*>(box);
  667 + if ((trak->track_type() & SrsMp4TrackTypeAudio) == SrsMp4TrackTypeAudio) {
  668 + return trak;
  669 + }
  670 + }
  671 + }
  672 + return NULL;
  673 +}
  674 +
628 int SrsMp4MovieBox::nb_header() 675 int SrsMp4MovieBox::nb_header()
629 { 676 {
630 return SrsMp4Box::nb_header(); 677 return SrsMp4Box::nb_header();
@@ -659,6 +706,11 @@ SrsMp4MovieHeaderBox::~SrsMp4MovieHeaderBox() @@ -659,6 +706,11 @@ SrsMp4MovieHeaderBox::~SrsMp4MovieHeaderBox()
659 { 706 {
660 } 707 }
661 708
  709 +uint64_t SrsMp4MovieHeaderBox::duration()
  710 +{
  711 + return duration_in_tbn * 1000 / timescale;
  712 +}
  713 +
662 int SrsMp4MovieHeaderBox::nb_header() 714 int SrsMp4MovieHeaderBox::nb_header()
663 { 715 {
664 int size = SrsMp4FullBox::nb_header(); 716 int size = SrsMp4FullBox::nb_header();
@@ -686,12 +738,12 @@ int SrsMp4MovieHeaderBox::encode_header(SrsBuffer* buf) @@ -686,12 +738,12 @@ int SrsMp4MovieHeaderBox::encode_header(SrsBuffer* buf)
686 buf->write_8bytes(creation_time); 738 buf->write_8bytes(creation_time);
687 buf->write_8bytes(modification_time); 739 buf->write_8bytes(modification_time);
688 buf->write_4bytes(timescale); 740 buf->write_4bytes(timescale);
689 - buf->write_8bytes(duration); 741 + buf->write_8bytes(duration_in_tbn);
690 } else { 742 } else {
691 buf->write_4bytes((uint32_t)creation_time); 743 buf->write_4bytes((uint32_t)creation_time);
692 buf->write_4bytes((uint32_t)modification_time); 744 buf->write_4bytes((uint32_t)modification_time);
693 buf->write_4bytes(timescale); 745 buf->write_4bytes(timescale);
694 - buf->write_4bytes((uint32_t)duration); 746 + buf->write_4bytes((uint32_t)duration_in_tbn);
695 } 747 }
696 748
697 buf->write_4bytes(rate); 749 buf->write_4bytes(rate);
@@ -721,12 +773,12 @@ int SrsMp4MovieHeaderBox::decode_header(SrsBuffer* buf) @@ -721,12 +773,12 @@ int SrsMp4MovieHeaderBox::decode_header(SrsBuffer* buf)
721 creation_time = buf->read_8bytes(); 773 creation_time = buf->read_8bytes();
722 modification_time = buf->read_8bytes(); 774 modification_time = buf->read_8bytes();
723 timescale = buf->read_4bytes(); 775 timescale = buf->read_4bytes();
724 - duration = buf->read_8bytes(); 776 + duration_in_tbn = buf->read_8bytes();
725 } else { 777 } else {
726 creation_time = buf->read_4bytes(); 778 creation_time = buf->read_4bytes();
727 modification_time = buf->read_4bytes(); 779 modification_time = buf->read_4bytes();
728 timescale = buf->read_4bytes(); 780 timescale = buf->read_4bytes();
729 - duration = buf->read_4bytes(); 781 + duration_in_tbn = buf->read_4bytes();
730 } 782 }
731 783
732 rate = buf->read_4bytes(); 784 rate = buf->read_4bytes();
@@ -769,6 +821,18 @@ SrsMp4TrackHeaderBox::~SrsMp4TrackHeaderBox() @@ -769,6 +821,18 @@ SrsMp4TrackHeaderBox::~SrsMp4TrackHeaderBox()
769 { 821 {
770 } 822 }
771 823
  824 +SrsMp4TrackType SrsMp4TrackBox::track_type()
  825 +{
  826 + SrsMp4Box* box = get(SrsMp4BoxTypeMDIA);
  827 + if (!box) {
  828 + return SrsMp4TrackTypeForbidden;
  829 + }
  830 +
  831 + // TODO: Maybe should discovery all mdia boxes.
  832 + SrsMp4MediaBox* mdia = dynamic_cast<SrsMp4MediaBox*>(box);
  833 + return mdia->track_type();
  834 +}
  835 +
772 int SrsMp4TrackHeaderBox::nb_header() 836 int SrsMp4TrackHeaderBox::nb_header()
773 { 837 {
774 int size = SrsMp4FullBox::nb_header(); 838 int size = SrsMp4FullBox::nb_header();
@@ -962,6 +1026,23 @@ SrsMp4MediaBox::~SrsMp4MediaBox() @@ -962,6 +1026,23 @@ SrsMp4MediaBox::~SrsMp4MediaBox()
962 { 1026 {
963 } 1027 }
964 1028
  1029 +SrsMp4TrackType SrsMp4MediaBox::track_type()
  1030 +{
  1031 + SrsMp4Box* box = get(SrsMp4BoxTypeHDLR);
  1032 + if (!box) {
  1033 + return SrsMp4TrackTypeForbidden;
  1034 + }
  1035 +
  1036 + SrsMp4HandlerReferenceBox* hdlr = dynamic_cast<SrsMp4HandlerReferenceBox*>(box);
  1037 + if (hdlr->handler_type == SrsMp4HandlerTypeSOUN) {
  1038 + return SrsMp4TrackTypeAudio;
  1039 + } else if (hdlr->handler_type == SrsMp4HandlerTypeVIDE) {
  1040 + return SrsMp4TrackTypeVideo;
  1041 + } else {
  1042 + return SrsMp4TrackTypeForbidden;
  1043 + }
  1044 +}
  1045 +
965 SrsMp4MediaHeaderBox::SrsMp4MediaHeaderBox() 1046 SrsMp4MediaHeaderBox::SrsMp4MediaHeaderBox()
966 { 1047 {
967 type = SrsMp4BoxTypeMDHD; 1048 type = SrsMp4BoxTypeMDHD;
@@ -1084,12 +1165,12 @@ SrsMp4HandlerReferenceBox::~SrsMp4HandlerReferenceBox() @@ -1084,12 +1165,12 @@ SrsMp4HandlerReferenceBox::~SrsMp4HandlerReferenceBox()
1084 1165
1085 bool SrsMp4HandlerReferenceBox::is_video() 1166 bool SrsMp4HandlerReferenceBox::is_video()
1086 { 1167 {
1087 - return handler_type == SrsMp4BoxTypeVIDE; 1168 + return handler_type == SrsMp4HandlerTypeVIDE;
1088 } 1169 }
1089 1170
1090 bool SrsMp4HandlerReferenceBox::is_audio() 1171 bool SrsMp4HandlerReferenceBox::is_audio()
1091 { 1172 {
1092 - return handler_type == SrsMp4BoxTypeSOUN; 1173 + return handler_type == SrsMp4HandlerTypeSOUN;
1093 } 1174 }
1094 1175
1095 int SrsMp4HandlerReferenceBox::nb_header() 1176 int SrsMp4HandlerReferenceBox::nb_header()
@@ -1124,7 +1205,7 @@ int SrsMp4HandlerReferenceBox::decode_header(SrsBuffer* buf) @@ -1124,7 +1205,7 @@ int SrsMp4HandlerReferenceBox::decode_header(SrsBuffer* buf)
1124 } 1205 }
1125 1206
1126 buf->skip(4); 1207 buf->skip(4);
1127 - handler_type = buf->read_4bytes(); 1208 + handler_type = (SrsMp4HandlerType)buf->read_4bytes();
1128 buf->skip(12); 1209 buf->skip(12);
1129 1210
1130 if ((ret = srs_mp4_string_read(buf, name, left_space(buf))) != ERROR_SUCCESS) { 1211 if ((ret = srs_mp4_string_read(buf, name, left_space(buf))) != ERROR_SUCCESS) {
@@ -2766,6 +2847,24 @@ int SrsMp4Decoder::initialize(ISrsReader* r) @@ -2766,6 +2847,24 @@ int SrsMp4Decoder::initialize(ISrsReader* r)
2766 int SrsMp4Decoder::parse_moov(SrsMp4MovieBox* moov) 2847 int SrsMp4Decoder::parse_moov(SrsMp4MovieBox* moov)
2767 { 2848 {
2768 int ret = ERROR_SUCCESS; 2849 int ret = ERROR_SUCCESS;
  2850 +
  2851 + SrsMp4MovieHeaderBox* mvhd = moov->mvhd();
  2852 + if (!mvhd) {
  2853 + ret = ERROR_MP4_ILLEGAL_MOOV;
  2854 + srs_error("MP4 missing mvhd. ret=%d", ret);
  2855 + return ret;
  2856 + }
  2857 +
  2858 + SrsMp4TrackBox* vide = moov->video();
  2859 + SrsMp4TrackBox* soun = moov->audio();
  2860 + if (!vide && !soun) {
  2861 + ret = ERROR_MP4_ILLEGAL_MOOV;
  2862 + srs_error("MP4 missing audio and video track. ret=%d", ret);
  2863 + return ret;
  2864 + }
  2865 +
  2866 + srs_trace("MP4 moov dur=%dms, vide=%d, soun=%d", mvhd->duration(), vide != NULL, soun != NULL);
  2867 +
2769 return ret; 2868 return ret;
2770 } 2869 }
2771 2870
@@ -81,9 +81,18 @@ enum SrsMp4BoxType @@ -81,9 +81,18 @@ enum SrsMp4BoxType
81 SrsMp4BoxTypeMP4A = 0x6d703461, // 'mp4a' 81 SrsMp4BoxTypeMP4A = 0x6d703461, // 'mp4a'
82 SrsMp4BoxTypeESDS = 0x65736473, // 'esds' 82 SrsMp4BoxTypeESDS = 0x65736473, // 'esds'
83 SrsMp4BoxTypeUDTA = 0x75647461, // 'udta' 83 SrsMp4BoxTypeUDTA = 0x75647461, // 'udta'
  84 +};
  85 +
  86 +/**
  87 + * 8.4.3.3 Semantics
  88 + * ISO_IEC_14496-12-base-format-2012.pdf, page 37
  89 + */
  90 +enum SrsMp4HandlerType
  91 +{
  92 + SrsMp4HandlerTypeForbidden = 0x00,
84 93
85 - SrsMp4BoxTypeVIDE = 0x76696465, // 'vide'  
86 - SrsMp4BoxTypeSOUN = 0x736f756e, // 'soun' 94 + SrsMp4HandlerTypeVIDE = 0x76696465, // 'vide'
  95 + SrsMp4HandlerTypeSOUN = 0x736f756e, // 'soun'
87 }; 96 };
88 97
89 /** 98 /**
@@ -121,7 +130,7 @@ public: @@ -121,7 +130,7 @@ public:
121 SrsMp4BoxType type; 130 SrsMp4BoxType type;
122 // For box 'uuid'. 131 // For box 'uuid'.
123 uint8_t* usertype; 132 uint8_t* usertype;
124 -private: 133 +protected:
125 std::vector<SrsMp4Box*> boxes; 134 std::vector<SrsMp4Box*> boxes;
126 private: 135 private:
127 // The position at buffer to start demux the box. 136 // The position at buffer to start demux the box.
@@ -138,6 +147,9 @@ public: @@ -138,6 +147,9 @@ public:
138 virtual bool is_ftyp(); 147 virtual bool is_ftyp();
139 virtual bool is_moov(); 148 virtual bool is_moov();
140 virtual bool is_mdat(); 149 virtual bool is_mdat();
  150 + // Get the contained box of specific type.
  151 + // @return The first matched box.
  152 + virtual SrsMp4Box* get(SrsMp4BoxType bt);
141 /** 153 /**
142 * Discovery the box from buffer. 154 * Discovery the box from buffer.
143 * @param ppbox Output the discoveried box, which user must free it. 155 * @param ppbox Output the discoveried box, which user must free it.
@@ -252,6 +264,9 @@ protected: @@ -252,6 +264,9 @@ protected:
252 virtual int decode_header(SrsBuffer* buf); 264 virtual int decode_header(SrsBuffer* buf);
253 }; 265 };
254 266
  267 +class SrsMp4TrackBox;
  268 +class SrsMp4MovieHeaderBox;
  269 +
255 /** 270 /**
256 * 8.2.1 Movie Box (moov) 271 * 8.2.1 Movie Box (moov)
257 * ISO_IEC_14496-12-base-format-2012.pdf, page 30 272 * ISO_IEC_14496-12-base-format-2012.pdf, page 30
@@ -263,6 +278,13 @@ class SrsMp4MovieBox : public SrsMp4Box @@ -263,6 +278,13 @@ class SrsMp4MovieBox : public SrsMp4Box
263 public: 278 public:
264 SrsMp4MovieBox(); 279 SrsMp4MovieBox();
265 virtual ~SrsMp4MovieBox(); 280 virtual ~SrsMp4MovieBox();
  281 +public:
  282 + // Get the header of moov.
  283 + virtual SrsMp4MovieHeaderBox* mvhd();
  284 + // Get the first video track.
  285 + virtual SrsMp4TrackBox* video();
  286 + // Get the first audio track.
  287 + virtual SrsMp4TrackBox* audio();
266 protected: 288 protected:
267 virtual int nb_header(); 289 virtual int nb_header();
268 virtual int encode_header(SrsBuffer* buf); 290 virtual int encode_header(SrsBuffer* buf);
@@ -282,6 +304,7 @@ public: @@ -282,6 +304,7 @@ public:
282 // an integer that declares the most recent time the presentation was modified (in 304 // an integer that declares the most recent time the presentation was modified (in
283 // seconds since midnight, Jan. 1, 1904, in UTC time) 305 // seconds since midnight, Jan. 1, 1904, in UTC time)
284 uint64_t modification_time; 306 uint64_t modification_time;
  307 +private:
285 // an integer that specifies the time-scale for the entire presentation; this is the number of 308 // an integer that specifies the time-scale for the entire presentation; this is the number of
286 // time units that pass in one second. For example, a time coordinate system that measures time in 309 // time units that pass in one second. For example, a time coordinate system that measures time in
287 // sixtieths of a second has a time scale of 60. 310 // sixtieths of a second has a time scale of 60.
@@ -289,7 +312,7 @@ public: @@ -289,7 +312,7 @@ public:
289 // an integer that declares length of the presentation (in the indicated timescale). This property 312 // an integer that declares length of the presentation (in the indicated timescale). This property
290 // is derived from the presentation’s tracks: the value of this field corresponds to the duration of the 313 // is derived from the presentation’s tracks: the value of this field corresponds to the duration of the
291 // longest track in the presentation. If the duration cannot be determined then duration is set to all 1s. 314 // longest track in the presentation. If the duration cannot be determined then duration is set to all 1s.
292 - uint64_t duration; 315 + uint64_t duration_in_tbn;
293 public: 316 public:
294 // a fixed point 16.16 number that indicates the preferred rate to play the presentation; 1.0 317 // a fixed point 16.16 number that indicates the preferred rate to play the presentation; 1.0
295 // (0x00010000) is normal forward playback 318 // (0x00010000) is normal forward playback
@@ -309,12 +332,23 @@ public: @@ -309,12 +332,23 @@ public:
309 public: 332 public:
310 SrsMp4MovieHeaderBox(); 333 SrsMp4MovieHeaderBox();
311 virtual ~SrsMp4MovieHeaderBox(); 334 virtual ~SrsMp4MovieHeaderBox();
  335 +public:
  336 + // Get the duration in ms.
  337 + virtual uint64_t duration();
312 protected: 338 protected:
313 virtual int nb_header(); 339 virtual int nb_header();
314 virtual int encode_header(SrsBuffer* buf); 340 virtual int encode_header(SrsBuffer* buf);
315 virtual int decode_header(SrsBuffer* buf); 341 virtual int decode_header(SrsBuffer* buf);
316 }; 342 };
317 343
  344 +// The type of track, maybe combine of types.
  345 +enum SrsMp4TrackType
  346 +{
  347 + SrsMp4TrackTypeForbidden = 0x00,
  348 + SrsMp4TrackTypeAudio = 0x01,
  349 + SrsMp4TrackTypeVideo = 0x02,
  350 +};
  351 +
318 /** 352 /**
319 * 8.3.1 Track Box (trak) 353 * 8.3.1 Track Box (trak)
320 * ISO_IEC_14496-12-base-format-2012.pdf, page 32 354 * ISO_IEC_14496-12-base-format-2012.pdf, page 32
@@ -327,6 +361,11 @@ class SrsMp4TrackBox : public SrsMp4Box @@ -327,6 +361,11 @@ class SrsMp4TrackBox : public SrsMp4Box
327 public: 361 public:
328 SrsMp4TrackBox(); 362 SrsMp4TrackBox();
329 virtual ~SrsMp4TrackBox(); 363 virtual ~SrsMp4TrackBox();
  364 +public:
  365 + // Get the type of track, maybe combine of track type,
  366 + // for example, it maybe Audio|Video when contains both.
  367 + // Generally, only single type, no combination.
  368 + virtual SrsMp4TrackType track_type();
330 }; 369 };
331 370
332 /** 371 /**
@@ -458,6 +497,11 @@ class SrsMp4MediaBox : public SrsMp4Box @@ -458,6 +497,11 @@ class SrsMp4MediaBox : public SrsMp4Box
458 public: 497 public:
459 SrsMp4MediaBox(); 498 SrsMp4MediaBox();
460 virtual ~SrsMp4MediaBox(); 499 virtual ~SrsMp4MediaBox();
  500 +public:
  501 + // Get the type of track, maybe combine of track type,
  502 + // for example, it maybe Audio|Video when contains both.
  503 + // Generally, only single type, no combination.
  504 + virtual SrsMp4TrackType track_type();
461 }; 505 };
462 506
463 /** 507 /**
@@ -521,7 +565,7 @@ public: @@ -521,7 +565,7 @@ public:
521 // an integer containing one of the following values, or a value from a derived specification: 565 // an integer containing one of the following values, or a value from a derived specification:
522 // ‘vide’, Video track 566 // ‘vide’, Video track
523 // ‘soun’, Audio track 567 // ‘soun’, Audio track
524 - uint32_t handler_type; 568 + SrsMp4HandlerType handler_type;
525 uint32_t reserved[3]; 569 uint32_t reserved[3];
526 // a null-terminated string in UTF-8 characters which gives a human-readable name for the track 570 // a null-terminated string in UTF-8 characters which gives a human-readable name for the track
527 // type (for debugging and inspection purposes). 571 // type (for debugging and inspection purposes).