winlin

for #179, update the metadata of flv dvr file.

@@ -38,6 +38,11 @@ using namespace std; @@ -38,6 +38,11 @@ using namespace std;
38 #include <srs_kernel_codec.hpp> 38 #include <srs_kernel_codec.hpp>
39 #include <srs_kernel_flv.hpp> 39 #include <srs_kernel_flv.hpp>
40 #include <srs_kernel_file.hpp> 40 #include <srs_kernel_file.hpp>
  41 +#include <srs_rtmp_amf0.hpp>
  42 +#include <srs_kernel_stream.hpp>
  43 +
  44 +// update the flv duration and filesize every this interval in ms.
  45 +#define __SRS_DVR_UPDATE_DURATION_INTERVAL 60000
41 46
42 SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p) 47 SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p)
43 { 48 {
@@ -58,6 +63,9 @@ SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p) @@ -58,6 +63,9 @@ SrsFlvSegment::SrsFlvSegment(SrsDvrPlan* p)
58 stream_previous_pkt_time = -1; 63 stream_previous_pkt_time = -1;
59 stream_duration = 0; 64 stream_duration = 0;
60 65
  66 + duration_offset = 0;
  67 + filesize_offset = 0;
  68 +
61 _srs_config->subscribe(this); 69 _srs_config->subscribe(this);
62 } 70 }
63 71
@@ -150,6 +158,10 @@ int SrsFlvSegment::open(bool use_tmp_file) @@ -150,6 +158,10 @@ int SrsFlvSegment::open(bool use_tmp_file)
150 return ret; 158 return ret;
151 } 159 }
152 } 160 }
  161 +
  162 + // update the duration and filesize offset.
  163 + duration_offset = 0;
  164 + filesize_offset = 0;
153 165
154 srs_trace("dvr stream %s to file %s", req->stream.c_str(), path.c_str()); 166 srs_trace("dvr stream %s to file %s", req->stream.c_str(), path.c_str());
155 167
@@ -164,6 +176,11 @@ int SrsFlvSegment::close() @@ -164,6 +176,11 @@ int SrsFlvSegment::close()
164 if (!fs->is_open()) { 176 if (!fs->is_open()) {
165 return ret; 177 return ret;
166 } 178 }
  179 +
  180 + // update duration and filesize.
  181 + if ((ret = update_flv_metadata()) != ERROR_SUCCESS) {
  182 + return ret;
  183 + }
167 184
168 fs->close(); 185 fs->close();
169 186
@@ -203,17 +220,61 @@ int SrsFlvSegment::close() @@ -203,17 +220,61 @@ int SrsFlvSegment::close()
203 return ret; 220 return ret;
204 } 221 }
205 222
206 -int SrsFlvSegment::write_metadata(SrsOnMetaDataPacket* metadata) 223 +int SrsFlvSegment::write_metadata(SrsSharedPtrMessage* metadata)
207 { 224 {
208 int ret = ERROR_SUCCESS; 225 int ret = ERROR_SUCCESS;
209 -  
210 - int size = 0;  
211 - char* payload = NULL;  
212 - if ((ret = metadata->encode(size, payload)) != ERROR_SUCCESS) { 226 +
  227 + if (duration_offset || filesize_offset) {
  228 + return ret;
  229 + }
  230 +
  231 + SrsStream stream;
  232 + if ((ret = stream.initialize(metadata->payload, metadata->size)) != ERROR_SUCCESS) {
  233 + return ret;
  234 + }
  235 +
  236 + SrsAmf0Any* name = SrsAmf0Any::str();
  237 + SrsAutoFree(SrsAmf0Any, name);
  238 + if ((ret = name->read(&stream)) != ERROR_SUCCESS) {
213 return ret; 239 return ret;
214 } 240 }
  241 +
  242 + SrsAmf0Object* obj = SrsAmf0Any::object();
  243 + SrsAutoFree(SrsAmf0Object, obj);
  244 + if ((ret = obj->read(&stream)) != ERROR_SUCCESS) {
  245 + return ret;
  246 + }
  247 +
  248 + // remove duration and filesize.
  249 + obj->set("filesize", NULL);
  250 + obj->set("duration", NULL);
  251 +
  252 + // add properties.
  253 + obj->set("service", SrsAmf0Any::str(RTMP_SIG_SRS_SERVER));
  254 + obj->set("filesize", SrsAmf0Any::number(0));
  255 + obj->set("duration", SrsAmf0Any::number(0));
  256 +
  257 + int size = name->total_size() + obj->total_size();
  258 + char* payload = new char[size];
215 SrsAutoFree(char, payload); 259 SrsAutoFree(char, payload);
  260 +
  261 + // 11B flv header, 3B object EOF, 8B number value, 1B number flag.
  262 + duration_offset = fs->tellg() + size + 11 - SrsAmf0Size::object_eof() - SrsAmf0Size::number();
  263 + // 2B string flag, 8B number value, 8B string 'duration', 1B number flag
  264 + filesize_offset = duration_offset - SrsAmf0Size::utf8("duration") - SrsAmf0Size::number();
  265 +
  266 + // convert metadata to bytes.
  267 + if ((ret = stream.initialize(payload, size)) != ERROR_SUCCESS) {
  268 + return ret;
  269 + }
  270 + if ((ret = name->write(&stream)) != ERROR_SUCCESS) {
  271 + return ret;
  272 + }
  273 + if ((ret = obj->write(&stream)) != ERROR_SUCCESS) {
  274 + return ret;
  275 + }
216 276
  277 + // to flv file.
217 if ((ret = enc->write_metadata(18, payload, size)) != ERROR_SUCCESS) { 278 if ((ret = enc->write_metadata(18, payload, size)) != ERROR_SUCCESS) {
218 return ret; 279 return ret;
219 } 280 }
@@ -287,6 +348,62 @@ int SrsFlvSegment::write_video(SrsSharedPtrMessage* __video) @@ -287,6 +348,62 @@ int SrsFlvSegment::write_video(SrsSharedPtrMessage* __video)
287 return ret; 348 return ret;
288 } 349 }
289 350
  351 +int SrsFlvSegment::update_flv_metadata()
  352 +{
  353 + int ret = ERROR_SUCCESS;
  354 +
  355 + // no duration or filesize specified.
  356 + if (!duration_offset || !filesize_offset) {
  357 + return ret;
  358 + }
  359 +
  360 + int64_t cur = fs->tellg();
  361 +
  362 + // buffer to write the size.
  363 + char* buf = new char[SrsAmf0Size::number()];
  364 + SrsAutoFree(char, buf);
  365 +
  366 + SrsStream stream;
  367 + if ((ret = stream.initialize(buf, SrsAmf0Size::number())) != ERROR_SUCCESS) {
  368 + return ret;
  369 + }
  370 +
  371 + // filesize to buf.
  372 + SrsAmf0Any* size = SrsAmf0Any::number((double)cur);
  373 + SrsAutoFree(SrsAmf0Any, size);
  374 +
  375 + stream.skip(-1 * stream.pos());
  376 + if ((ret = size->write(&stream)) != ERROR_SUCCESS) {
  377 + return ret;
  378 + }
  379 +
  380 + // update the flesize.
  381 + fs->lseek(filesize_offset);
  382 + if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
  383 + return ret;
  384 + }
  385 +
  386 + // duration to buf
  387 + SrsAmf0Any* dur = SrsAmf0Any::number((double)duration / 1000.0);
  388 + SrsAutoFree(SrsAmf0Any, dur);
  389 +
  390 + stream.skip(-1 * stream.pos());
  391 + if ((ret = dur->write(&stream)) != ERROR_SUCCESS) {
  392 + return ret;
  393 + }
  394 +
  395 + // update the duration
  396 + fs->lseek(duration_offset);
  397 + if ((ret = fs->write(buf, SrsAmf0Size::number(), NULL)) != ERROR_SUCCESS) {
  398 + return ret;
  399 + }
  400 +
  401 + // reset the offset.
  402 + fs->lseek(cur);
  403 +
  404 + return ret;
  405 +}
  406 +
290 string SrsFlvSegment::generate_path() 407 string SrsFlvSegment::generate_path()
291 { 408 {
292 // the path in config, for example, 409 // the path in config, for example,
@@ -498,7 +615,7 @@ int64_t SrsDvrPlan::filter_timestamp(int64_t timestamp) @@ -498,7 +615,7 @@ int64_t SrsDvrPlan::filter_timestamp(int64_t timestamp)
498 return timestamp; 615 return timestamp;
499 } 616 }
500 617
501 -int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata) 618 +int SrsDvrPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
502 { 619 {
503 int ret = ERROR_SUCCESS; 620 int ret = ERROR_SUCCESS;
504 621
@@ -506,7 +623,7 @@ int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata) @@ -506,7 +623,7 @@ int SrsDvrPlan::on_meta_data(SrsOnMetaDataPacket* metadata)
506 return ret; 623 return ret;
507 } 624 }
508 625
509 - return segment->write_metadata(metadata); 626 + return segment->write_metadata(__metadata);
510 } 627 }
511 628
512 int SrsDvrPlan::on_audio(SrsSharedPtrMessage* __audio) 629 int SrsDvrPlan::on_audio(SrsSharedPtrMessage* __audio)
@@ -606,6 +723,7 @@ void SrsDvrSessionPlan::on_unpublish() @@ -606,6 +723,7 @@ void SrsDvrSessionPlan::on_unpublish()
606 723
607 SrsDvrAppendPlan::SrsDvrAppendPlan() 724 SrsDvrAppendPlan::SrsDvrAppendPlan()
608 { 725 {
  726 + last_update_time = 0;
609 } 727 }
610 728
611 SrsDvrAppendPlan::~SrsDvrAppendPlan() 729 SrsDvrAppendPlan::~SrsDvrAppendPlan()
@@ -638,16 +756,74 @@ void SrsDvrAppendPlan::on_unpublish() @@ -638,16 +756,74 @@ void SrsDvrAppendPlan::on_unpublish()
638 { 756 {
639 } 757 }
640 758
  759 +int SrsDvrAppendPlan::on_audio(SrsSharedPtrMessage* audio)
  760 +{
  761 + int ret = ERROR_SUCCESS;
  762 +
  763 + if ((ret = update_duration(audio)) != ERROR_SUCCESS) {
  764 + return ret;
  765 + }
  766 +
  767 + if ((ret = SrsDvrPlan::on_audio(audio)) != ERROR_SUCCESS) {
  768 + return ret;
  769 + }
  770 +
  771 + return ret;
  772 +}
  773 +
  774 +int SrsDvrAppendPlan::on_video(SrsSharedPtrMessage* video)
  775 +{
  776 + int ret = ERROR_SUCCESS;
  777 +
  778 + if ((ret = update_duration(video)) != ERROR_SUCCESS) {
  779 + return ret;
  780 + }
  781 +
  782 + if ((ret = SrsDvrPlan::on_video(video)) != ERROR_SUCCESS) {
  783 + return ret;
  784 + }
  785 +
  786 + return ret;
  787 +}
  788 +
  789 +int SrsDvrAppendPlan::update_duration(SrsSharedPtrMessage* msg)
  790 +{
  791 + int ret = ERROR_SUCCESS;
  792 +
  793 + if (last_update_time <= 0) {
  794 + last_update_time = msg->timestamp;
  795 + return ret;
  796 + }
  797 +
  798 + if (msg->timestamp < last_update_time) {
  799 + last_update_time = msg->timestamp;
  800 + return ret;
  801 + }
  802 +
  803 + if (__SRS_DVR_UPDATE_DURATION_INTERVAL > msg->timestamp - last_update_time) {
  804 + return ret;
  805 + }
  806 + last_update_time = msg->timestamp;
  807 +
  808 + srs_assert(segment);
  809 + if (!segment->update_flv_metadata()) {
  810 + return ret;
  811 + }
  812 +
  813 + return ret;
  814 +}
  815 +
641 SrsDvrSegmentPlan::SrsDvrSegmentPlan() 816 SrsDvrSegmentPlan::SrsDvrSegmentPlan()
642 { 817 {
643 segment_duration = -1; 818 segment_duration = -1;
644 - sh_video = sh_audio = NULL; 819 + metadata = sh_video = sh_audio = NULL;
645 } 820 }
646 821
647 SrsDvrSegmentPlan::~SrsDvrSegmentPlan() 822 SrsDvrSegmentPlan::~SrsDvrSegmentPlan()
648 { 823 {
649 srs_freep(sh_video); 824 srs_freep(sh_video);
650 srs_freep(sh_audio); 825 srs_freep(sh_audio);
  826 + srs_freep(metadata);
651 } 827 }
652 828
653 int SrsDvrSegmentPlan::initialize(SrsSource* source, SrsRequest* req) 829 int SrsDvrSegmentPlan::initialize(SrsSource* source, SrsRequest* req)
@@ -695,6 +871,20 @@ void SrsDvrSegmentPlan::on_unpublish() @@ -695,6 +871,20 @@ void SrsDvrSegmentPlan::on_unpublish()
695 { 871 {
696 } 872 }
697 873
  874 +int SrsDvrSegmentPlan::on_meta_data(SrsSharedPtrMessage* __metadata)
  875 +{
  876 + int ret = ERROR_SUCCESS;
  877 +
  878 + srs_freep(metadata);
  879 + metadata = __metadata->copy();
  880 +
  881 + if ((ret = SrsDvrPlan::on_meta_data(__metadata)) != ERROR_SUCCESS) {
  882 + return ret;
  883 + }
  884 +
  885 + return ret;
  886 +}
  887 +
698 int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* audio) 888 int SrsDvrSegmentPlan::on_audio(SrsSharedPtrMessage* audio)
699 { 889 {
700 int ret = ERROR_SUCCESS; 890 int ret = ERROR_SUCCESS;
@@ -774,6 +964,9 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) @@ -774,6 +964,9 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
774 } 964 }
775 965
776 // update sequence header 966 // update sequence header
  967 + if (metadata && (ret = SrsDvrPlan::on_meta_data(metadata)) != ERROR_SUCCESS) {
  968 + return ret;
  969 + }
777 if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) { 970 if (sh_video && (ret = SrsDvrPlan::on_video(sh_video)) != ERROR_SUCCESS) {
778 return ret; 971 return ret;
779 } 972 }
@@ -828,8 +1021,19 @@ void SrsDvr::on_unpublish() @@ -828,8 +1021,19 @@ void SrsDvr::on_unpublish()
828 int SrsDvr::on_meta_data(SrsOnMetaDataPacket* m) 1021 int SrsDvr::on_meta_data(SrsOnMetaDataPacket* m)
829 { 1022 {
830 int ret = ERROR_SUCCESS; 1023 int ret = ERROR_SUCCESS;
831 -  
832 - if ((ret = plan->on_meta_data(m)) != ERROR_SUCCESS) { 1024 +
  1025 + int size = 0;
  1026 + char* payload = NULL;
  1027 + if ((ret = m->encode(size, payload)) != ERROR_SUCCESS) {
  1028 + return ret;
  1029 + }
  1030 +
  1031 + SrsSharedPtrMessage metadata;
  1032 + if ((ret = metadata.create(NULL, payload, size)) != ERROR_SUCCESS) {
  1033 + return ret;
  1034 + }
  1035 +
  1036 + if ((ret = plan->on_meta_data(&metadata)) != ERROR_SUCCESS) {
833 return ret; 1037 return ret;
834 } 1038 }
835 1039
@@ -67,6 +67,17 @@ private: @@ -67,6 +67,17 @@ private:
67 SrsRtmpJitterAlgorithm jitter_algorithm; 67 SrsRtmpJitterAlgorithm jitter_algorithm;
68 SrsFileWriter* fs; 68 SrsFileWriter* fs;
69 private: 69 private:
  70 + /**
  71 + * the offset of file for duration value.
  72 + * the next 8 bytes is the double value.
  73 + */
  74 + int64_t duration_offset;
  75 + /**
  76 + * the offset of file for filesize value.
  77 + * the next 8 bytes is the double value.
  78 + */
  79 + int64_t filesize_offset;
  80 +private:
70 std::string tmp_flv_file; 81 std::string tmp_flv_file;
71 private: 82 private:
72 /** 83 /**
@@ -124,7 +135,7 @@ public: @@ -124,7 +135,7 @@ public:
124 /** 135 /**
125 * write the metadata to segment. 136 * write the metadata to segment.
126 */ 137 */
127 - virtual int write_metadata(SrsOnMetaDataPacket* metadata); 138 + virtual int write_metadata(SrsSharedPtrMessage* metadata);
128 /** 139 /**
129 * @param __audio, directly ptr, copy it if need to save it. 140 * @param __audio, directly ptr, copy it if need to save it.
130 */ 141 */
@@ -133,6 +144,10 @@ public: @@ -133,6 +144,10 @@ public:
133 * @param __video, directly ptr, copy it if need to save it. 144 * @param __video, directly ptr, copy it if need to save it.
134 */ 145 */
135 virtual int write_video(SrsSharedPtrMessage* __video); 146 virtual int write_video(SrsSharedPtrMessage* __video);
  147 + /**
  148 + * update the flv metadata.
  149 + */
  150 + virtual int update_flv_metadata();
136 private: 151 private:
137 /** 152 /**
138 * generate the flv segment path. 153 * generate the flv segment path.
@@ -178,7 +193,7 @@ public: @@ -178,7 +193,7 @@ public:
178 /** 193 /**
179 * when got metadata. 194 * when got metadata.
180 */ 195 */
181 - virtual int on_meta_data(SrsOnMetaDataPacket* metadata); 196 + virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
182 /** 197 /**
183 * @param __audio, directly ptr, copy it if need to save it. 198 * @param __audio, directly ptr, copy it if need to save it.
184 */ 199 */
@@ -213,12 +228,24 @@ public: @@ -213,12 +228,24 @@ public:
213 */ 228 */
214 class SrsDvrAppendPlan : public SrsDvrPlan 229 class SrsDvrAppendPlan : public SrsDvrPlan
215 { 230 {
  231 +private:
  232 + int64_t last_update_time;
216 public: 233 public:
217 SrsDvrAppendPlan(); 234 SrsDvrAppendPlan();
218 virtual ~SrsDvrAppendPlan(); 235 virtual ~SrsDvrAppendPlan();
219 public: 236 public:
220 virtual int on_publish(); 237 virtual int on_publish();
221 virtual void on_unpublish(); 238 virtual void on_unpublish();
  239 + /**
  240 + * @param audio, directly ptr, copy it if need to save it.
  241 + */
  242 + virtual int on_audio(SrsSharedPtrMessage* audio);
  243 + /**
  244 + * @param video, directly ptr, copy it if need to save it.
  245 + */
  246 + virtual int on_video(SrsSharedPtrMessage* video);
  247 +private:
  248 + virtual int update_duration(SrsSharedPtrMessage* msg);
222 }; 249 };
223 250
224 /** 251 /**
@@ -231,6 +258,7 @@ private: @@ -231,6 +258,7 @@ private:
231 int segment_duration; 258 int segment_duration;
232 SrsSharedPtrMessage* sh_audio; 259 SrsSharedPtrMessage* sh_audio;
233 SrsSharedPtrMessage* sh_video; 260 SrsSharedPtrMessage* sh_video;
  261 + SrsSharedPtrMessage* metadata;
234 public: 262 public:
235 SrsDvrSegmentPlan(); 263 SrsDvrSegmentPlan();
236 virtual ~SrsDvrSegmentPlan(); 264 virtual ~SrsDvrSegmentPlan();
@@ -239,6 +267,10 @@ public: @@ -239,6 +267,10 @@ public:
239 virtual int on_publish(); 267 virtual int on_publish();
240 virtual void on_unpublish(); 268 virtual void on_unpublish();
241 /** 269 /**
  270 + * when got metadata.
  271 + */
  272 + virtual int on_meta_data(SrsSharedPtrMessage* __metadata);
  273 + /**
242 * @param audio, directly ptr, copy it if need to save it. 274 * @param audio, directly ptr, copy it if need to save it.
243 */ 275 */
244 virtual int on_audio(SrsSharedPtrMessage* audio); 276 virtual int on_audio(SrsSharedPtrMessage* audio);
@@ -116,6 +116,11 @@ bool SrsFileWriter::is_open() @@ -116,6 +116,11 @@ bool SrsFileWriter::is_open()
116 return fd > 0; 116 return fd > 0;
117 } 117 }
118 118
  119 +void SrsFileWriter::lseek(int64_t offset)
  120 +{
  121 + ::lseek(fd, (off_t)offset, SEEK_SET);
  122 +}
  123 +
119 int64_t SrsFileWriter::tellg() 124 int64_t SrsFileWriter::tellg()
120 { 125 {
121 return (int64_t)::lseek(fd, 0, SEEK_CUR); 126 return (int64_t)::lseek(fd, 0, SEEK_CUR);
@@ -54,6 +54,7 @@ public: @@ -54,6 +54,7 @@ public:
54 virtual void close(); 54 virtual void close();
55 public: 55 public:
56 virtual bool is_open(); 56 virtual bool is_open();
  57 + virtual void lseek(int64_t offset);
57 virtual int64_t tellg(); 58 virtual int64_t tellg();
58 public: 59 public:
59 /** 60 /**
@@ -448,11 +448,6 @@ SrsAmf0Any* SrsUnSortedHashtable::value_at(int index) @@ -448,11 +448,6 @@ SrsAmf0Any* SrsUnSortedHashtable::value_at(int index)
448 448
449 void SrsUnSortedHashtable::set(string key, SrsAmf0Any* value) 449 void SrsUnSortedHashtable::set(string key, SrsAmf0Any* value)
450 { 450 {
451 - if (!value) {  
452 - srs_warn("add a NULL propertity %s", key.c_str());  
453 - return;  
454 - }  
455 -  
456 std::vector<SrsAmf0ObjectPropertyType>::iterator it; 451 std::vector<SrsAmf0ObjectPropertyType>::iterator it;
457 452
458 for (it = properties.begin(); it != properties.end(); ++it) { 453 for (it = properties.begin(); it != properties.end(); ++it) {
@@ -467,7 +462,9 @@ void SrsUnSortedHashtable::set(string key, SrsAmf0Any* value) @@ -467,7 +462,9 @@ void SrsUnSortedHashtable::set(string key, SrsAmf0Any* value)
467 } 462 }
468 } 463 }
469 464
470 - properties.push_back(std::make_pair(key, value)); 465 + if (value) {
  466 + properties.push_back(std::make_pair(key, value));
  467 + }
471 } 468 }
472 469
473 SrsAmf0Any* SrsUnSortedHashtable::get_property(string name) 470 SrsAmf0Any* SrsUnSortedHashtable::get_property(string name)
@@ -794,6 +794,10 @@ namespace _srs_internal @@ -794,6 +794,10 @@ namespace _srs_internal
794 virtual std::string key_at(int index); 794 virtual std::string key_at(int index);
795 virtual const char* key_raw_at(int index); 795 virtual const char* key_raw_at(int index);
796 virtual SrsAmf0Any* value_at(int index); 796 virtual SrsAmf0Any* value_at(int index);
  797 + /**
  798 + * set the value of hashtable.
  799 + * @param value, the value to set. NULL to delete the property.
  800 + */
797 virtual void set(std::string key, SrsAmf0Any* value); 801 virtual void set(std::string key, SrsAmf0Any* value);
798 public: 802 public:
799 virtual SrsAmf0Any* get_property(std::string name); 803 virtual SrsAmf0Any* get_property(std::string name);
@@ -434,7 +434,6 @@ int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int si @@ -434,7 +434,6 @@ int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int si
434 { 434 {
435 int ret = ERROR_SUCCESS; 435 int ret = ERROR_SUCCESS;
436 436
437 - srs_assert(pheader != NULL);  
438 if (ptr) { 437 if (ptr) {
439 ret = ERROR_SYSTEM_ASSERT_FAILED; 438 ret = ERROR_SYSTEM_ASSERT_FAILED;
440 srs_error("should not set the payload twice. ret=%d", ret); 439 srs_error("should not set the payload twice. ret=%d", ret);
@@ -446,11 +445,13 @@ int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int si @@ -446,11 +445,13 @@ int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int si
446 ptr = new __SrsSharedPtr(); 445 ptr = new __SrsSharedPtr();
447 446
448 // direct attach the data. 447 // direct attach the data.
449 - ptr->header.message_type = pheader->message_type;  
450 - ptr->header.payload_length = size;  
451 - ptr->header.perfer_cid = pheader->perfer_cid;  
452 - this->timestamp = pheader->timestamp;  
453 - this->stream_id = pheader->stream_id; 448 + if (pheader) {
  449 + ptr->header.message_type = pheader->message_type;
  450 + ptr->header.payload_length = size;
  451 + ptr->header.perfer_cid = pheader->perfer_cid;
  452 + this->timestamp = pheader->timestamp;
  453 + this->stream_id = pheader->stream_id;
  454 + }
454 ptr->payload = payload; 455 ptr->payload = payload;
455 ptr->size = size; 456 ptr->size = size;
456 457
@@ -283,6 +283,7 @@ public: @@ -283,6 +283,7 @@ public:
283 * create shared ptr message, 283 * create shared ptr message,
284 * from the header and payload. 284 * from the header and payload.
285 * @remark user should never free the payload. 285 * @remark user should never free the payload.
  286 + * @param pheader, the header to copy to the message. NULL to ignore.
286 */ 287 */
287 virtual int create(SrsMessageHeader* pheader, char* payload, int size); 288 virtual int create(SrsMessageHeader* pheader, char* payload, int size);
288 /** 289 /**