winlin

for bug #251, the shared ptr message share the header. 2.0.64

@@ -213,7 +213,7 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* __audio) @@ -213,7 +213,7 @@ int SrsDvrPlan::on_audio(SrsSharedPtrMessage* __audio)
213 213
214 char* payload = audio->payload; 214 char* payload = audio->payload;
215 int size = audio->size; 215 int size = audio->size;
216 - int64_t timestamp = filter_timestamp(audio->header.timestamp); 216 + int64_t timestamp = filter_timestamp(audio->timestamp);
217 if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) { 217 if ((ret = enc->write_audio(timestamp, payload, size)) != ERROR_SUCCESS) {
218 return ret; 218 return ret;
219 } 219 }
@@ -262,7 +262,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video) @@ -262,7 +262,7 @@ int SrsDvrPlan::on_video(SrsSharedPtrMessage* __video)
262 return ret; 262 return ret;
263 } 263 }
264 264
265 - int32_t timestamp = filter_timestamp(video->header.timestamp); 265 + int32_t timestamp = filter_timestamp(video->timestamp);
266 if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) { 266 if ((ret = enc->write_video(timestamp, payload, size)) != ERROR_SUCCESS) {
267 return ret; 267 return ret;
268 } 268 }
@@ -332,20 +332,20 @@ int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg) @@ -332,20 +332,20 @@ int SrsDvrPlan::update_duration(SrsSharedPtrMessage* msg)
332 332
333 // set the segment starttime at first time 333 // set the segment starttime at first time
334 if (segment->starttime < 0) { 334 if (segment->starttime < 0) {
335 - segment->starttime = msg->header.timestamp; 335 + segment->starttime = msg->timestamp;
336 } 336 }
337 337
338 // no previous packet or timestamp overflow. 338 // no previous packet or timestamp overflow.
339 - if (segment->stream_previous_pkt_time < 0 || segment->stream_previous_pkt_time > msg->header.timestamp) {  
340 - segment->stream_previous_pkt_time = msg->header.timestamp; 339 + if (segment->stream_previous_pkt_time < 0 || segment->stream_previous_pkt_time > msg->timestamp) {
  340 + segment->stream_previous_pkt_time = msg->timestamp;
341 } 341 }
342 342
343 // collect segment and stream duration, timestamp overflow is ok. 343 // collect segment and stream duration, timestamp overflow is ok.
344 - segment->duration += msg->header.timestamp - segment->stream_previous_pkt_time;  
345 - segment->stream_duration += msg->header.timestamp - segment->stream_previous_pkt_time; 344 + segment->duration += msg->timestamp - segment->stream_previous_pkt_time;
  345 + segment->stream_duration += msg->timestamp - segment->stream_previous_pkt_time;
346 346
347 // update previous packet time 347 // update previous packet time
348 - segment->stream_previous_pkt_time = msg->header.timestamp; 348 + segment->stream_previous_pkt_time = msg->timestamp;
349 349
350 return ret; 350 return ret;
351 } 351 }
@@ -488,7 +488,7 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg) @@ -488,7 +488,7 @@ int SrsDvrSegmentPlan::update_duration(SrsSharedPtrMessage* msg)
488 // when wait keyframe, ignore if no frame arrived. 488 // when wait keyframe, ignore if no frame arrived.
489 // @see https://github.com/winlinvip/simple-rtmp-server/issues/177 489 // @see https://github.com/winlinvip/simple-rtmp-server/issues/177
490 if (_srs_config->get_dvr_wait_keyframe(_req->vhost)) { 490 if (_srs_config->get_dvr_wait_keyframe(_req->vhost)) {
491 - if (!msg->header.is_video()) { 491 + if (!msg->is_video()) {
492 return ret; 492 return ret;
493 } 493 }
494 494
@@ -560,7 +560,7 @@ int SrsEdgeForwarder::proxy(SrsCommonMessage* msg) @@ -560,7 +560,7 @@ int SrsEdgeForwarder::proxy(SrsCommonMessage* msg)
560 } 560 }
561 srs_verbose("initialize shared ptr msg success."); 561 srs_verbose("initialize shared ptr msg success.");
562 562
563 - copy.header.stream_id = stream_id; 563 + copy.stream_id = stream_id;
564 if ((ret = queue->enqueue(copy.copy())) != ERROR_SUCCESS) { 564 if ((ret = queue->enqueue(copy.copy())) != ERROR_SUCCESS) {
565 srs_error("enqueue edge publish msg failed. ret=%d", ret); 565 srs_error("enqueue edge publish msg failed. ret=%d", ret);
566 } 566 }
@@ -1458,7 +1458,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* __audio) @@ -1458,7 +1458,7 @@ int SrsHls::on_audio(SrsSharedPtrMessage* __audio)
1458 } 1458 }
1459 1459
1460 // the pts calc from rtmp/flv header. 1460 // the pts calc from rtmp/flv header.
1461 - int64_t pts = audio->header.timestamp * 90; 1461 + int64_t pts = audio->timestamp * 90;
1462 1462
1463 // for pure audio, we need to update the stream dts also. 1463 // for pure audio, we need to update the stream dts also.
1464 stream_dts = pts; 1464 stream_dts = pts;
@@ -1503,7 +1503,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* __video) @@ -1503,7 +1503,7 @@ int SrsHls::on_video(SrsSharedPtrMessage* __video)
1503 return ret; 1503 return ret;
1504 } 1504 }
1505 1505
1506 - int64_t dts = video->header.timestamp * 90; 1506 + int64_t dts = video->timestamp * 90;
1507 stream_dts = dts; 1507 stream_dts = dts;
1508 if ((ret = hls_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) { 1508 if ((ret = hls_cache->write_video(codec, muxer, dts, sample)) != ERROR_SUCCESS) {
1509 srs_error("hls cache write video failed. ret=%d", ret); 1509 srs_error("hls cache write video failed. ret=%d", ret);
@@ -642,11 +642,11 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd) @@ -642,11 +642,11 @@ int SrsRtmpConn::do_playing(SrsSource* source, SrsQueueRecvThread* trd)
642 642
643 // foreach msg, collect the duration. 643 // foreach msg, collect the duration.
644 // @remark: never use msg when sent it, for the protocol sdk will free it. 644 // @remark: never use msg when sent it, for the protocol sdk will free it.
645 - if (starttime < 0 || starttime > msg->header.timestamp) {  
646 - starttime = msg->header.timestamp; 645 + if (starttime < 0 || starttime > msg->timestamp) {
  646 + starttime = msg->timestamp;
647 } 647 }
648 - duration += msg->header.timestamp - starttime;  
649 - starttime = msg->header.timestamp; 648 + duration += msg->timestamp - starttime;
  649 + starttime = msg->timestamp;
650 } 650 }
651 } 651 }
652 652
@@ -85,10 +85,10 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi @@ -85,10 +85,10 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi
85 if (ag == SrsRtmpJitterAlgorithmZERO) { 85 if (ag == SrsRtmpJitterAlgorithmZERO) {
86 // for the first time, last_pkt_correct_time is zero. 86 // for the first time, last_pkt_correct_time is zero.
87 // while when timestamp overflow, the timestamp become smaller, reset the last_pkt_correct_time. 87 // while when timestamp overflow, the timestamp become smaller, reset the last_pkt_correct_time.
88 - if (last_pkt_correct_time <= 0 || last_pkt_correct_time > msg->header.timestamp) {  
89 - last_pkt_correct_time = msg->header.timestamp; 88 + if (last_pkt_correct_time <= 0 || last_pkt_correct_time > msg->timestamp) {
  89 + last_pkt_correct_time = msg->timestamp;
90 } 90 }
91 - msg->header.timestamp -= last_pkt_correct_time; 91 + msg->timestamp -= last_pkt_correct_time;
92 return ret; 92 return ret;
93 } 93 }
94 94
@@ -99,8 +99,8 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi @@ -99,8 +99,8 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi
99 // full jitter algorithm, do jitter correct. 99 // full jitter algorithm, do jitter correct.
100 100
101 // set to 0 for metadata. 101 // set to 0 for metadata.
102 - if (!msg->header.is_audio() && !msg->header.is_video()) {  
103 - msg->header.timestamp = 0; 102 + if (!msg->is_av()) {
  103 + msg->timestamp = 0;
104 return ret; 104 return ret;
105 } 105 }
106 106
@@ -117,15 +117,15 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi @@ -117,15 +117,15 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi
117 * 3. last_pkt_correct_time: simply add the positive delta, 117 * 3. last_pkt_correct_time: simply add the positive delta,
118 * and enforce the time monotonically. 118 * and enforce the time monotonically.
119 */ 119 */
120 - int64_t time = msg->header.timestamp; 120 + int64_t time = msg->timestamp;
121 int64_t delta = time - last_pkt_time; 121 int64_t delta = time - last_pkt_time;
122 122
123 // if jitter detected, reset the delta. 123 // if jitter detected, reset the delta.
124 if (delta < 0 || delta > CONST_MAX_JITTER_MS) { 124 if (delta < 0 || delta > CONST_MAX_JITTER_MS) {
125 // calc the right diff by audio sample rate 125 // calc the right diff by audio sample rate
126 - if (msg->header.is_audio() && sample_rate > 0) { 126 + if (msg->is_audio() && sample_rate > 0) {
127 delta = (int64_t)(delta * 1000.0 / sample_rate); 127 delta = (int64_t)(delta * 1000.0 / sample_rate);
128 - } else if (msg->header.is_video() && frame_rate > 0) { 128 + } else if (msg->is_video() && frame_rate > 0) {
129 delta = (int64_t)(delta * 1.0 / frame_rate); 129 delta = (int64_t)(delta * 1.0 / frame_rate);
130 } else { 130 } else {
131 delta = DEFAULT_FRAME_TIME_MS; 131 delta = DEFAULT_FRAME_TIME_MS;
@@ -145,7 +145,7 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi @@ -145,7 +145,7 @@ int SrsRtmpJitter::correct(SrsSharedPtrMessage* msg, int tba, int tbv, SrsRtmpJi
145 145
146 last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta); 146 last_pkt_correct_time = srs_max(0, last_pkt_correct_time + delta);
147 147
148 - msg->header.timestamp = last_pkt_correct_time; 148 + msg->timestamp = last_pkt_correct_time;
149 last_pkt_time = time; 149 last_pkt_time = time;
150 150
151 return ret; 151 return ret;
@@ -186,12 +186,12 @@ int SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg) @@ -186,12 +186,12 @@ int SrsMessageQueue::enqueue(SrsSharedPtrMessage* msg)
186 { 186 {
187 int ret = ERROR_SUCCESS; 187 int ret = ERROR_SUCCESS;
188 188
189 - if (msg->header.is_audio() || msg->header.is_video()) { 189 + if (msg->is_av()) {
190 if (av_start_time == -1) { 190 if (av_start_time == -1) {
191 - av_start_time = msg->header.timestamp; 191 + av_start_time = msg->timestamp;
192 } 192 }
193 193
194 - av_end_time = msg->header.timestamp; 194 + av_end_time = msg->timestamp;
195 } 195 }
196 196
197 msgs.push_back(msg); 197 msgs.push_back(msg);
@@ -221,7 +221,7 @@ int SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, in @@ -221,7 +221,7 @@ int SrsMessageQueue::dump_packets(int max_count, SrsSharedPtrMessage** pmsgs, in
221 } 221 }
222 222
223 SrsSharedPtrMessage* last = omsgs[count - 1]; 223 SrsSharedPtrMessage* last = omsgs[count - 1];
224 - av_start_time = last->header.timestamp; 224 + av_start_time = last->timestamp;
225 225
226 if (count >= nb_msgs) { 226 if (count >= nb_msgs) {
227 // the pmsgs is big enough and clear msgs at most time. 227 // the pmsgs is big enough and clear msgs at most time.
@@ -248,13 +248,13 @@ void SrsMessageQueue::shrink() @@ -248,13 +248,13 @@ void SrsMessageQueue::shrink()
248 for (int i = 1; i < (int)msgs.size(); i++) { 248 for (int i = 1; i < (int)msgs.size(); i++) {
249 SrsSharedPtrMessage* msg = msgs[i]; 249 SrsSharedPtrMessage* msg = msgs[i];
250 250
251 - if (msg->header.is_video()) { 251 + if (msg->is_video()) {
252 if (SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) { 252 if (SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) {
253 // the max frame index to remove. 253 // the max frame index to remove.
254 iframe_index = i; 254 iframe_index = i;
255 255
256 // set the start time, we will remove until this frame. 256 // set the start time, we will remove until this frame.
257 - av_start_time = msg->header.timestamp; 257 + av_start_time = msg->timestamp;
258 258
259 break; 259 break;
260 } 260 }
@@ -471,7 +471,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* __msg) @@ -471,7 +471,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* __msg)
471 } 471 }
472 472
473 // got video, update the video count if acceptable 473 // got video, update the video count if acceptable
474 - if (msg->header.is_video()) { 474 + if (msg->is_video()) {
475 cached_video_count++; 475 cached_video_count++;
476 audio_after_last_video_count = 0; 476 audio_after_last_video_count = 0;
477 } 477 }
@@ -483,7 +483,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* __msg) @@ -483,7 +483,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* __msg)
483 } 483 }
484 484
485 // ok, gop cache enabled, and got an audio. 485 // ok, gop cache enabled, and got an audio.
486 - if (msg->header.is_audio()) { 486 + if (msg->is_audio()) {
487 audio_after_last_video_count++; 487 audio_after_last_video_count++;
488 } 488 }
489 489
@@ -495,7 +495,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* __msg) @@ -495,7 +495,7 @@ int SrsGopCache::cache(SrsSharedPtrMessage* __msg)
495 } 495 }
496 496
497 // clear gop cache when got key frame 497 // clear gop cache when got key frame
498 - if (msg->header.is_video() && SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) { 498 + if (msg->is_video() && SrsFlvCodec::video_is_keyframe(msg->payload, msg->size)) {
499 srs_info("clear gop cache when got keyframe. vcount=%d, count=%d", 499 srs_info("clear gop cache when got keyframe. vcount=%d, count=%d",
500 cached_video_count, (int)gop_cache.size()); 500 cached_video_count, (int)gop_cache.size());
501 501
@@ -556,7 +556,7 @@ int64_t SrsGopCache::start_time() @@ -556,7 +556,7 @@ int64_t SrsGopCache::start_time()
556 SrsSharedPtrMessage* msg = gop_cache[0]; 556 SrsSharedPtrMessage* msg = gop_cache[0];
557 srs_assert(msg); 557 srs_assert(msg);
558 558
559 - return msg->header.timestamp; 559 + return msg->timestamp;
560 } 560 }
561 561
562 bool SrsGopCache::pure_audio() 562 bool SrsGopCache::pure_audio()
@@ -1239,7 +1239,7 @@ int SrsSource::on_audio(SrsCommonMessage* __audio) @@ -1239,7 +1239,7 @@ int SrsSource::on_audio(SrsCommonMessage* __audio)
1239 srs_trace("%dB audio sh, " 1239 srs_trace("%dB audio sh, "
1240 "codec(%d, profile=%d, %dchannels, %dkbps, %dHZ), " 1240 "codec(%d, profile=%d, %dchannels, %dkbps, %dHZ), "
1241 "flv(%dbits, %dchannels, %dHZ)", 1241 "flv(%dbits, %dchannels, %dHZ)",
1242 - msg.header.payload_length, codec.audio_codec_id, 1242 + msg.size, codec.audio_codec_id,
1243 codec.aac_profile, codec.aac_channels, 1243 codec.aac_profile, codec.aac_channels,
1244 codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate], 1244 codec.audio_data_rate / 1000, aac_sample_rates[codec.aac_sample_rate],
1245 flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type], 1245 flv_sample_sizes[sample.sound_size], flv_sound_types[sample.sound_type],
@@ -1257,10 +1257,10 @@ int SrsSource::on_audio(SrsCommonMessage* __audio) @@ -1257,10 +1257,10 @@ int SrsSource::on_audio(SrsCommonMessage* __audio)
1257 // if atc, update the sequence header to abs time. 1257 // if atc, update the sequence header to abs time.
1258 if (atc) { 1258 if (atc) {
1259 if (cache_sh_audio) { 1259 if (cache_sh_audio) {
1260 - cache_sh_audio->header.timestamp = msg.header.timestamp; 1260 + cache_sh_audio->timestamp = msg.timestamp;
1261 } 1261 }
1262 if (cache_metadata) { 1262 if (cache_metadata) {
1263 - cache_metadata->header.timestamp = msg.header.timestamp; 1263 + cache_metadata->timestamp = msg.timestamp;
1264 } 1264 }
1265 } 1265 }
1266 1266
@@ -1352,7 +1352,7 @@ int SrsSource::on_video(SrsCommonMessage* __video) @@ -1352,7 +1352,7 @@ int SrsSource::on_video(SrsCommonMessage* __video)
1352 1352
1353 srs_trace("%dB video sh, " 1353 srs_trace("%dB video sh, "
1354 "codec(%d, profile=%d, level=%d, %dx%d, %dkbps, %dfps, %ds)", 1354 "codec(%d, profile=%d, level=%d, %dx%d, %dkbps, %dfps, %ds)",
1355 - msg.header.payload_length, codec.video_codec_id, 1355 + msg.size, codec.video_codec_id,
1356 codec.avc_profile, codec.avc_level, codec.width, codec.height, 1356 codec.avc_profile, codec.avc_level, codec.width, codec.height,
1357 codec.video_data_rate / 1000, codec.frame_rate, codec.duration); 1357 codec.video_data_rate / 1000, codec.frame_rate, codec.duration);
1358 return ret; 1358 return ret;
@@ -1368,10 +1368,10 @@ int SrsSource::on_video(SrsCommonMessage* __video) @@ -1368,10 +1368,10 @@ int SrsSource::on_video(SrsCommonMessage* __video)
1368 // if atc, update the sequence header to abs time. 1368 // if atc, update the sequence header to abs time.
1369 if (atc) { 1369 if (atc) {
1370 if (cache_sh_video) { 1370 if (cache_sh_video) {
1371 - cache_sh_video->header.timestamp = msg.header.timestamp; 1371 + cache_sh_video->timestamp = msg.timestamp;
1372 } 1372 }
1373 if (cache_metadata) { 1373 if (cache_metadata) {
1374 - cache_metadata->header.timestamp = msg.header.timestamp; 1374 + cache_metadata->timestamp = msg.timestamp;
1375 } 1375 }
1376 } 1376 }
1377 1377
@@ -1593,13 +1593,13 @@ void SrsSource::on_unpublish() @@ -1593,13 +1593,13 @@ void SrsSource::on_unpublish()
1593 // if atc, update the sequence header to gop cache time. 1593 // if atc, update the sequence header to gop cache time.
1594 if (atc && !gop_cache->empty()) { 1594 if (atc && !gop_cache->empty()) {
1595 if (cache_metadata) { 1595 if (cache_metadata) {
1596 - cache_metadata->header.timestamp = gop_cache->start_time(); 1596 + cache_metadata->timestamp = gop_cache->start_time();
1597 } 1597 }
1598 if (cache_sh_video) { 1598 if (cache_sh_video) {
1599 - cache_sh_video->header.timestamp = gop_cache->start_time(); 1599 + cache_sh_video->timestamp = gop_cache->start_time();
1600 } 1600 }
1601 if (cache_sh_audio) { 1601 if (cache_sh_audio) {
1602 - cache_sh_audio->header.timestamp = gop_cache->start_time(); 1602 + cache_sh_audio->timestamp = gop_cache->start_time();
1603 } 1603 }
1604 } 1604 }
1605 1605
@@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31 // current release version 31 // current release version
32 #define VERSION_MAJOR 2 32 #define VERSION_MAJOR 2
33 #define VERSION_MINOR 0 33 #define VERSION_MINOR 0
34 -#define VERSION_REVISION 63 34 +#define VERSION_REVISION 64
35 // server info. 35 // server info.
36 #define RTMP_SIG_SRS_KEY "SRS" 36 #define RTMP_SIG_SRS_KEY "SRS"
37 #define RTMP_SIG_SRS_ROLE "origin/edge server" 37 #define RTMP_SIG_SRS_ROLE "origin/edge server"
@@ -96,7 +96,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. @@ -96,7 +96,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
96 * that is, 1+4=5bytes. 96 * that is, 1+4=5bytes.
97 */ 97 */
98 // always use fmt0 as cache. 98 // always use fmt0 as cache.
99 -//#define SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE 5 99 +#define SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE 5
100 100
101 /** 101 /**
102 * for performance issue, 102 * for performance issue,
@@ -405,21 +405,25 @@ SrsSharedPtrMessage::__SrsSharedPtr::~__SrsSharedPtr() @@ -405,21 +405,25 @@ SrsSharedPtrMessage::__SrsSharedPtr::~__SrsSharedPtr()
405 } 405 }
406 406
407 #ifdef SRS_PERF_MW_MSG_IOVS_CACHE 407 #ifdef SRS_PERF_MW_MSG_IOVS_CACHE
408 -int SrsSharedPtrMessage::__SrsSharedPtr::mic_evaluate(  
409 - SrsMessageHeader* mh, int chunk_size  
410 -) { 408 +int SrsSharedPtrMessage::__SrsSharedPtr::mic_evaluate(int chunk_size)
  409 +{
411 int ret = ERROR_SUCCESS; 410 int ret = ERROR_SUCCESS;
412 411
413 // use the chunk size, shuold not be changed. 412 // use the chunk size, shuold not be changed.
414 this->chunk_size = chunk_size; 413 this->chunk_size = chunk_size;
415 414
416 - // ignore size  
417 - srs_chunk_header(mic_c0, mh, true);  
418 - mic_c3 = 0xC0 | (mh->perfer_cid & 0x3F); 415 + // c0 header
  416 + int nbh = srs_chunk_header_c0(
  417 + header.perfer_cid, 0, header.payload_length,
  418 + header.message_type, 0,
  419 + mic_c0, sizeof(mic_c0));
  420 + srs_assert(nbh > 0);;
  421 + // c3 header
  422 + mic_c3 = 0xC0 | (header.perfer_cid & 0x3F);
419 423
420 // calc number of iovs 424 // calc number of iovs
421 - nb_chunks = mh->payload_length / chunk_size;  
422 - if (mh->payload_length % chunk_size) { 425 + nb_chunks = header.payload_length / chunk_size;
  426 + if (header.payload_length % chunk_size) {
423 nb_chunks++; 427 nb_chunks++;
424 } 428 }
425 nb_iovs = 1/*cid*/ + 1/*size*//*type*/+ 1/*chunk*/; 429 nb_iovs = 1/*cid*/ + 1/*size*//*type*/+ 1/*chunk*/;
@@ -529,12 +533,14 @@ int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int si @@ -529,12 +533,14 @@ int SrsSharedPtrMessage::create(SrsMessageHeader* pheader, char* payload, int si
529 return ret; 533 return ret;
530 } 534 }
531 535
532 - header = *pheader;  
533 - header.payload_length = size;  
534 -  
535 ptr = new __SrsSharedPtr(); 536 ptr = new __SrsSharedPtr();
536 537
537 // direct attach the data. 538 // direct attach the data.
  539 + ptr->header.message_type = pheader->message_type;
  540 + ptr->header.payload_length = size;
  541 + ptr->header.perfer_cid = pheader->perfer_cid;
  542 + this->timestamp = pheader->timestamp;
  543 + this->stream_id = pheader->stream_id;
538 ptr->payload = payload; 544 ptr->payload = payload;
539 ptr->size = size; 545 ptr->size = size;
540 546
@@ -551,17 +557,68 @@ int SrsSharedPtrMessage::count() @@ -551,17 +557,68 @@ int SrsSharedPtrMessage::count()
551 return ptr->shared_count; 557 return ptr->shared_count;
552 } 558 }
553 559
  560 +bool SrsSharedPtrMessage::check(int stream_id)
  561 +{
  562 + // we donot use the complex basic header,
  563 + // ensure the basic header is 1bytes.
  564 + if (ptr->header.perfer_cid < 2) {
  565 + srs_info("change the chunk_id=%d to default=%d",
  566 + ptr->header.perfer_cid, RTMP_CID_ProtocolControl);
  567 + ptr->header.perfer_cid = RTMP_CID_ProtocolControl;
  568 + }
  569 +
  570 + // we assume that the stream_id in a group must be the same.
  571 + if (this->stream_id == stream_id) {
  572 + return true;
  573 + }
  574 + this->stream_id = stream_id;
  575 +
  576 + return false;
  577 +}
  578 +
  579 +bool SrsSharedPtrMessage::is_av()
  580 +{
  581 + return ptr->header.message_type == RTMP_MSG_AudioMessage
  582 + || ptr->header.message_type == RTMP_MSG_VideoMessage;
  583 +}
  584 +
  585 +bool SrsSharedPtrMessage::is_audio()
  586 +{
  587 + return ptr->header.message_type == RTMP_MSG_AudioMessage;
  588 +}
  589 +
  590 +bool SrsSharedPtrMessage::is_video()
  591 +{
  592 + return ptr->header.message_type == RTMP_MSG_VideoMessage;
  593 +}
  594 +
  595 +#ifndef SRS_PERF_MW_MSG_IOVS_CACHE
  596 +int SrsSharedPtrMessage::chunk_header(char* cache, int nb_cache, bool c0)
  597 +{
  598 + if (c0) {
  599 + return srs_chunk_header_c0(
  600 + ptr->header.perfer_cid, timestamp, ptr->header.payload_length,
  601 + ptr->header.message_type, stream_id,
  602 + cache, nb_cache);
  603 + } else {
  604 + return srs_chunk_header_c3(
  605 + ptr->header.perfer_cid, timestamp,
  606 + cache, nb_cache);
  607 + }
  608 +}
  609 +#endif
  610 +
554 SrsSharedPtrMessage* SrsSharedPtrMessage::copy() 611 SrsSharedPtrMessage* SrsSharedPtrMessage::copy()
555 { 612 {
556 srs_assert(ptr); 613 srs_assert(ptr);
557 614
558 SrsSharedPtrMessage* copy = new SrsSharedPtrMessage(); 615 SrsSharedPtrMessage* copy = new SrsSharedPtrMessage();
559 616
560 - copy->header = header;  
561 -  
562 copy->ptr = ptr; 617 copy->ptr = ptr;
563 ptr->shared_count++; 618 ptr->shared_count++;
564 619
  620 + copy->timestamp = timestamp;
  621 + copy->stream_id = stream_id;
565 copy->payload = ptr->payload; 622 copy->payload = ptr->payload;
566 copy->size = ptr->size; 623 copy->size = ptr->size;
567 624
@@ -583,7 +640,7 @@ int SrsSharedPtrMessage::mic_evaluate(int chunk_size) @@ -583,7 +640,7 @@ int SrsSharedPtrMessage::mic_evaluate(int chunk_size)
583 640
584 // calc the shared ptr iovs at the first time. 641 // calc the shared ptr iovs at the first time.
585 if (ptr->chunk_size <= 0) { 642 if (ptr->chunk_size <= 0) {
586 - if ((ret = ptr->mic_evaluate(&header, chunk_size)) != ERROR_SUCCESS) { 643 + if ((ret = ptr->mic_evaluate(chunk_size)) != ERROR_SUCCESS) {
587 srs_warn("mic evaluate source iovs failed. ret=%d", ret); 644 srs_warn("mic evaluate source iovs failed. ret=%d", ret);
588 return ret; 645 return ret;
589 } 646 }
@@ -610,7 +667,7 @@ int SrsSharedPtrMessage::mic_iovs_dump(iovec* iovs, int max_nb_iovs) @@ -610,7 +667,7 @@ int SrsSharedPtrMessage::mic_iovs_dump(iovec* iovs, int max_nb_iovs)
610 } 667 }
611 668
612 // timestamp for c0/c3 669 // timestamp for c0/c3
613 - u_int32_t timestamp = (u_int32_t)header.timestamp; 670 + u_int32_t timestamp = (u_int32_t)this->timestamp;
614 mic_etime_present = timestamp >= RTMP_EXTENDED_TIMESTAMP; 671 mic_etime_present = timestamp >= RTMP_EXTENDED_TIMESTAMP;
615 672
616 // chunk message header, 11 bytes 673 // chunk message header, 11 bytes
@@ -629,7 +686,7 @@ int SrsSharedPtrMessage::mic_iovs_dump(iovec* iovs, int max_nb_iovs) @@ -629,7 +686,7 @@ int SrsSharedPtrMessage::mic_iovs_dump(iovec* iovs, int max_nb_iovs)
629 686
630 // stream_id, 4bytes, little-endian 687 // stream_id, 4bytes, little-endian
631 p = mic_c0_sid; 688 p = mic_c0_sid;
632 - pp = (char*)&header.stream_id; 689 + pp = (char*)&stream_id;
633 *p++ = pp[0]; 690 *p++ = pp[0];
634 *p++ = pp[1]; 691 *p++ = pp[1];
635 *p++ = pp[2]; 692 *p++ = pp[2];
@@ -964,14 +1021,6 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -964,14 +1021,6 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
964 srs_info("ignore empty message."); 1021 srs_info("ignore empty message.");
965 continue; 1022 continue;
966 } 1023 }
967 -  
968 - // we donot use the complex basic header,  
969 - // ensure the basic header is 1bytes.  
970 - if (msg->header.perfer_cid < 2) {  
971 - srs_info("change the chunk_id=%d to default=%d",  
972 - msg->header.perfer_cid, RTMP_CID_ProtocolControl);  
973 - msg->header.perfer_cid = RTMP_CID_ProtocolControl;  
974 - }  
975 1024
976 // p set to current write position, 1025 // p set to current write position,
977 // it's ok when payload is NULL and size is 0. 1026 // it's ok when payload is NULL and size is 0.
@@ -981,7 +1030,8 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -981,7 +1030,8 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
981 // always write the header event payload is empty. 1030 // always write the header event payload is empty.
982 while (p < pend) { 1031 while (p < pend) {
983 // always has header 1032 // always has header
984 - int nbh = srs_chunk_header(c0c3_cache, &msg->header, p == msg->payload); 1033 + int nb_cache = SRS_CONSTS_C0C3_HEADERS_MAX - c0c3_cache_index;
  1034 + int nbh = msg->chunk_header(c0c3_cache, nb_cache, p == msg->payload);
985 srs_assert(nbh > 0); 1035 srs_assert(nbh > 0);
986 1036
987 // header iov 1037 // header iov
@@ -1066,8 +1116,8 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs) @@ -1066,8 +1116,8 @@ int SrsProtocol::do_send_messages(SrsSharedPtrMessage** msgs, int nb_msgs)
1066 for (int i = msg_sent; i < nb_msgs; i++) { 1116 for (int i = msg_sent; i < nb_msgs; i++) {
1067 SrsSharedPtrMessage* msg = msgs[i]; 1117 SrsSharedPtrMessage* msg = msgs[i];
1068 1118
1069 - // evaluate  
1070 - if ((ret = msg->mic_evaluate(out_chunk_size)) != ERROR_SUCCESS) { 1119 + // evaluate the first
  1120 + if (i == 0 && (ret = msg->mic_evaluate(out_chunk_size)) != ERROR_SUCCESS) {
1071 return ret; 1121 return ret;
1072 } 1122 }
1073 1123
@@ -1185,7 +1235,18 @@ int SrsProtocol::do_simple_send(SrsMessageHeader* mh, char* payload, int size) @@ -1185,7 +1235,18 @@ int SrsProtocol::do_simple_send(SrsMessageHeader* mh, char* payload, int size)
1185 char* end = p + size; 1235 char* end = p + size;
1186 char c0c3[SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE]; 1236 char c0c3[SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE];
1187 while (p < end) { 1237 while (p < end) {
1188 - int nbh = srs_chunk_header(c0c3, mh, p == payload); 1238 + int nbh = 0;
  1239 + if (p == payload) {
  1240 + nbh = srs_chunk_header_c0(
  1241 + mh->perfer_cid, mh->timestamp, mh->payload_length,
  1242 + mh->message_type, mh->stream_id,
  1243 + c0c3, sizeof(c0c3));
  1244 + } else {
  1245 + nbh = srs_chunk_header_c3(
  1246 + mh->perfer_cid, mh->timestamp,
  1247 + c0c3, sizeof(c0c3));
  1248 + }
  1249 + srs_assert(nbh > 0);;
1189 1250
1190 iovec iovs[2]; 1251 iovec iovs[2];
1191 iovs[0].iov_base = c0c3; 1252 iovs[0].iov_base = c0c3;
@@ -1388,11 +1449,12 @@ int SrsProtocol::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs, @@ -1388,11 +1449,12 @@ int SrsProtocol::send_and_free_messages(SrsSharedPtrMessage** msgs, int nb_msgs,
1388 // update the stream id in header. 1449 // update the stream id in header.
1389 for (int i = 0; i < nb_msgs; i++) { 1450 for (int i = 0; i < nb_msgs; i++) {
1390 SrsSharedPtrMessage* msg = msgs[i]; 1451 SrsSharedPtrMessage* msg = msgs[i];
1391 - // we assume that the stream_id in a group must be the same.  
1392 - if (msg->header.stream_id == stream_id) { 1452 +
  1453 + // check perfer cid and stream,
  1454 + // when one msg stream id is ok, ignore left.
  1455 + if (msg->check(stream_id)) {
1393 break; 1456 break;
1394 } 1457 }
1395 - msg->header.stream_id = stream_id;  
1396 } 1458 }
1397 1459
1398 // donot use the auto free to free the msg, 1460 // donot use the auto free to free the msg,
@@ -182,6 +182,32 @@ public: @@ -182,6 +182,32 @@ public:
182 }; 182 };
183 183
184 /** 184 /**
  185 +* the message header for shared ptr message.
  186 +* only the message for all msgs are same.
  187 +*/
  188 +struct SrsSharedMessageHeader
  189 +{
  190 + /**
  191 + * 3bytes.
  192 + * Three-byte field that represents the size of the payload in bytes.
  193 + * It is set in big-endian format.
  194 + */
  195 + int32_t payload_length;
  196 + /**
  197 + * 1byte.
  198 + * One byte field to represent the message type. A range of type IDs
  199 + * (1-7) are reserved for protocol control messages.
  200 + */
  201 + int8_t message_type;
  202 + /**
  203 + * get the perfered cid(chunk stream id) which sendout over.
  204 + * set at decoding, and canbe used for directly send message,
  205 + * for example, dispatch to all connections.
  206 + */
  207 + int perfer_cid;
  208 +};
  209 +
  210 +/**
185 * shared ptr message. 211 * shared ptr message.
186 * for audio/video/data message that need less memory copy. 212 * for audio/video/data message that need less memory copy.
187 * and only for output. 213 * and only for output.
@@ -194,7 +220,22 @@ class SrsSharedPtrMessage @@ -194,7 +220,22 @@ class SrsSharedPtrMessage
194 { 220 {
195 // 4.1. Message Header 221 // 4.1. Message Header
196 public: 222 public:
197 - SrsMessageHeader header; 223 + // the header can shared, only set the timestamp and stream id.
  224 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/251
  225 + //SrsSharedMessageHeader header;
  226 + /**
  227 + * Four-byte field that contains a timestamp of the message.
  228 + * The 4 bytes are packed in the big-endian order.
  229 + * @remark, used as calc timestamp when decode and encode time.
  230 + * @remark, we use 64bits for large time for jitter detect and hls.
  231 + */
  232 + int64_t timestamp;
  233 + /**
  234 + * 4bytes.
  235 + * Four-byte field that identifies the stream of the message. These
  236 + * bytes are set in big-endian format.
  237 + */
  238 + int32_t stream_id;
198 // 4.2. Message Payload 239 // 4.2. Message Payload
199 public: 240 public:
200 /** 241 /**
@@ -214,6 +255,9 @@ private: @@ -214,6 +255,9 @@ private:
214 class __SrsSharedPtr 255 class __SrsSharedPtr
215 { 256 {
216 public: 257 public:
  258 + // shared message header.
  259 + // @see https://github.com/winlinvip/simple-rtmp-server/issues/251
  260 + SrsSharedMessageHeader header;
217 // actual shared payload. 261 // actual shared payload.
218 char* payload; 262 char* payload;
219 // size of payload. 263 // size of payload.
@@ -269,7 +313,7 @@ private: @@ -269,7 +313,7 @@ private:
269 * for iovs msg cache, calc the iovs. 313 * for iovs msg cache, calc the iovs.
270 * @param chunk_size use the specified chunk size to evaluate the iovs. 314 * @param chunk_size use the specified chunk size to evaluate the iovs.
271 */ 315 */
272 - virtual int mic_evaluate(SrsMessageHeader* mh, int chunk_size); 316 + virtual int mic_evaluate(int chunk_size);
273 #endif 317 #endif
274 }; 318 };
275 __SrsSharedPtr* ptr; 319 __SrsSharedPtr* ptr;
@@ -312,6 +356,23 @@ public: @@ -312,6 +356,23 @@ public:
312 * @remark, assert object is created. 356 * @remark, assert object is created.
313 */ 357 */
314 virtual int count(); 358 virtual int count();
  359 + /**
  360 + * check perfer cid and stream id.
  361 + * @return whether stream id already set.
  362 + */
  363 + virtual bool check(int stream_id);
  364 +public:
  365 + virtual bool is_av();
  366 + virtual bool is_audio();
  367 + virtual bool is_video();
  368 +public:
  369 +#ifndef SRS_PERF_MW_MSG_IOVS_CACHE
  370 + /**
  371 + * generate the chunk header to cache.
  372 + * @return the size of header.
  373 + */
  374 + virtual int chunk_header(char* cache, int nb_cache, bool c0);
  375 +#endif
315 public: 376 public:
316 /** 377 /**
317 * copy current shared ptr message, use ref-count. 378 * copy current shared ptr message, use ref-count.
@@ -204,7 +204,11 @@ bool srs_aac_startswith_adts(SrsStream* stream) @@ -204,7 +204,11 @@ bool srs_aac_startswith_adts(SrsStream* stream)
204 return true; 204 return true;
205 } 205 }
206 206
207 -int srs_chunk_header(char* cache, SrsMessageHeader* mh, bool c0) 207 +int srs_chunk_header_c0(
  208 + int perfer_cid, u_int32_t timestamp, int32_t payload_length,
  209 + int8_t message_type, int32_t stream_id,
  210 + char* cache, int nb_cache
  211 +)
208 { 212 {
209 // to directly set the field. 213 // to directly set the field.
210 char* pp = NULL; 214 char* pp = NULL;
@@ -212,48 +216,94 @@ int srs_chunk_header(char* cache, SrsMessageHeader* mh, bool c0) @@ -212,48 +216,94 @@ int srs_chunk_header(char* cache, SrsMessageHeader* mh, bool c0)
212 // generate the header. 216 // generate the header.
213 char* p = cache; 217 char* p = cache;
214 218
215 - // timestamp for c0/c3  
216 - u_int32_t timestamp = (u_int32_t)mh->timestamp; 219 + // no header.
  220 + if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT0_HEADER_SIZE) {
  221 + return 0;
  222 + }
217 223
218 - if (c0) {  
219 - // write new chunk stream header, fmt is 0  
220 - *p++ = 0x00 | (mh->perfer_cid & 0x3F);  
221 -  
222 - // chunk message header, 11 bytes  
223 - // timestamp, 3bytes, big-endian  
224 - if (timestamp < RTMP_EXTENDED_TIMESTAMP) {  
225 - pp = (char*)&timestamp;  
226 - *p++ = pp[2];  
227 - *p++ = pp[1];  
228 - *p++ = pp[0];  
229 - } else {  
230 - *p++ = 0xFF;  
231 - *p++ = 0xFF;  
232 - *p++ = 0xFF;  
233 - }  
234 -  
235 - // message_length, 3bytes, big-endian  
236 - pp = (char*)&mh->payload_length; 224 + // write new chunk stream header, fmt is 0
  225 + *p++ = 0x00 | (perfer_cid & 0x3F);
  226 +
  227 + // chunk message header, 11 bytes
  228 + // timestamp, 3bytes, big-endian
  229 + if (timestamp < RTMP_EXTENDED_TIMESTAMP) {
  230 + pp = (char*)&timestamp;
237 *p++ = pp[2]; 231 *p++ = pp[2];
238 *p++ = pp[1]; 232 *p++ = pp[1];
239 *p++ = pp[0]; 233 *p++ = pp[0];
240 -  
241 - // message_type, 1bytes  
242 - *p++ = mh->message_type;  
243 -  
244 - // stream_id, 4bytes, little-endian  
245 - pp = (char*)&mh->stream_id;  
246 - *p++ = pp[0];  
247 - *p++ = pp[1];  
248 - *p++ = pp[2];  
249 - *p++ = pp[3];  
250 } else { 234 } else {
251 - // write no message header chunk stream, fmt is 3  
252 - // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,  
253 - // SRS will rollback to 1B chunk header.  
254 - *p++ = 0xC0 | (mh->perfer_cid & 0x3F); 235 + *p++ = 0xFF;
  236 + *p++ = 0xFF;
  237 + *p++ = 0xFF;
255 } 238 }
256 239
  240 + // message_length, 3bytes, big-endian
  241 + pp = (char*)&payload_length;
  242 + *p++ = pp[2];
  243 + *p++ = pp[1];
  244 + *p++ = pp[0];
  245 +
  246 + // message_type, 1bytes
  247 + *p++ = message_type;
  248 +
  249 + // stream_id, 4bytes, little-endian
  250 + pp = (char*)&stream_id;
  251 + *p++ = pp[0];
  252 + *p++ = pp[1];
  253 + *p++ = pp[2];
  254 + *p++ = pp[3];
  255 +
  256 + // for c0
  257 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  258 + //
  259 + // for c3:
  260 + // chunk extended timestamp header, 0 or 4 bytes, big-endian
  261 + // 6.1.3. Extended Timestamp
  262 + // This field is transmitted only when the normal time stamp in the
  263 + // chunk message header is set to 0x00ffffff. If normal time stamp is
  264 + // set to any value less than 0x00ffffff, this field MUST NOT be
  265 + // present. This field MUST NOT be present if the timestamp field is not
  266 + // present. Type 3 chunks MUST NOT have this field.
  267 + // adobe changed for Type3 chunk:
  268 + // FMLE always sendout the extended-timestamp,
  269 + // must send the extended-timestamp to FMS,
  270 + // must send the extended-timestamp to flash-player.
  271 + // @see: ngx_rtmp_prepare_message
  272 + // @see: http://blog.csdn.net/win_lin/article/details/13363699
  273 + // TODO: FIXME: extract to outer.
  274 + if (timestamp >= RTMP_EXTENDED_TIMESTAMP) {
  275 + pp = (char*)&timestamp;
  276 + *p++ = pp[3];
  277 + *p++ = pp[2];
  278 + *p++ = pp[1];
  279 + *p++ = pp[0];
  280 + }
  281 +
  282 + // always has header
  283 + return p - cache;
  284 +}
  285 +
  286 +int srs_chunk_header_c3(
  287 + int perfer_cid, u_int32_t timestamp,
  288 + char* cache, int nb_cache
  289 +)
  290 +{
  291 + // to directly set the field.
  292 + char* pp = NULL;
  293 +
  294 + // generate the header.
  295 + char* p = cache;
  296 +
  297 + // no header.
  298 + if (nb_cache < SRS_CONSTS_RTMP_MAX_FMT3_HEADER_SIZE) {
  299 + return 0;
  300 + }
  301 +
  302 + // write no message header chunk stream, fmt is 3
  303 + // @remark, if perfer_cid > 0x3F, that is, use 2B/3B chunk header,
  304 + // SRS will rollback to 1B chunk header.
  305 + *p++ = 0xC0 | (perfer_cid & 0x3F);
  306 +
257 // for c0 307 // for c0
258 // chunk extended timestamp header, 0 or 4 bytes, big-endian 308 // chunk extended timestamp header, 0 or 4 bytes, big-endian
259 // 309 //
@@ -105,12 +105,27 @@ extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = N @@ -105,12 +105,27 @@ extern bool srs_avc_startswith_annexb(SrsStream* stream, int* pnb_start_code = N
105 extern bool srs_aac_startswith_adts(SrsStream* stream); 105 extern bool srs_aac_startswith_adts(SrsStream* stream);
106 106
107 /** 107 /**
108 -* generate the chunk header for msg.  
109 -* @param mh, the header of msg to send.  
110 -* @param c0, whether the first chunk, the c0 chunk.  
111 -* @return the size of header. 108 +* generate the c0 chunk header for msg.
  109 +* @param cache, the cache to write header.
  110 +* @param nb_cache, the size of cache.
  111 +* @return the size of header. 0 if cache not enough.
112 */ 112 */
113 -extern int srs_chunk_header(char* cache, SrsMessageHeader* mh, bool c0); 113 +extern int srs_chunk_header_c0(
  114 + int perfer_cid, u_int32_t timestamp, int32_t payload_length,
  115 + int8_t message_type, int32_t stream_id,
  116 + char* cache, int nb_cache
  117 +);
  118 +
  119 +/**
  120 +* generate the c3 chunk header for msg.
  121 +* @param cache, the cache to write header.
  122 +* @param nb_cache, the size of cache.
  123 +* @return the size of header. 0 if cache not enough.
  124 +*/
  125 +extern int srs_chunk_header_c3(
  126 + int perfer_cid, u_int32_t timestamp,
  127 + char* cache, int nb_cache
  128 +);
114 129
115 #endif 130 #endif
116 131