vp8rtpfmt.c 22.8 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
vp8rtpfmt.c

mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2011-2012 Belledonne Communications, Grenoble, France

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*/


#include "vp8rtpfmt.h"


jehan's avatar
jehan committed
26
/*#define VP8RTPFMT_DEBUG*/
27 28


29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
#ifdef VP8RTPFMT_DEBUG
static uint16_t get_partition_pictureid(Vp8RtpFmtPartition *partition) {
	Vp8RtpFmtPacket *packet = ms_list_nth_data(partition->packets_list, 0);
	return packet->pd->pictureid;
}

static uint8_t get_partition_id(Vp8RtpFmtPartition *partition) {
	Vp8RtpFmtPacket *packet = ms_list_nth_data(partition->packets_list, 0);
	return packet->pd->pid;
}

static int is_partition_non_reference(Vp8RtpFmtPartition *partition) {
	Vp8RtpFmtPacket *packet = ms_list_nth_data(partition->packets_list, 0);
	return packet->pd->non_reference_frame;
}

static uint32_t get_partition_ts(Vp8RtpFmtPartition *partition) {
	return mblk_get_timestamp_info(partition->m);
}

static uint16_t get_frame_pictureid(Vp8RtpFmtFrame *frame) {
	return get_partition_pictureid(ms_list_nth_data(frame->partitions_list, 0));
}

static int is_frame_non_reference(Vp8RtpFmtFrame *frame) {
	return is_partition_non_reference(ms_list_nth_data(frame->partitions_list, 0));
}

static uint32_t get_frame_ts(Vp8RtpFmtFrame *frame) {
	return get_partition_ts(ms_list_nth_data(frame->partitions_list, 0));
}

static void print_packet(void *data) {
	Vp8RtpFmtPacket *packet = (Vp8RtpFmtPacket *)data;
	ms_message("\t\tcseq=%10u\tS=%d\terror=%d",
		packet->extended_cseq, packet->pd->start_of_partition, packet->error);
}

static void print_partition(void *data) {
	Vp8RtpFmtPartition *partition = (Vp8RtpFmtPartition *)data;
	ms_message("\tpartition [%p]:\tpid=%d\tlast=%d\terror=%d",
		partition, get_partition_id(partition), partition->last_partition_of_frame, partition->error);
	ms_list_for_each(partition->packets_list, print_packet);
}

static void print_frame(void *data) {
	Vp8RtpFmtFrame *frame = (Vp8RtpFmtFrame *)data;
76 77
	ms_message("frame [%p]:\tts=%u\tpictureid=%u\tN=%d\terror=%d",
		frame, get_frame_ts(frame), get_frame_pictureid(frame), is_frame_non_reference(frame), frame->error);
78 79 80 81
	ms_list_for_each(frame->partitions_list, print_partition);
}
#endif /* VP8RTPFMT_DEBUG */

82 83
static void free_packet(void *data) {
	Vp8RtpFmtPacket *packet = (Vp8RtpFmtPacket *)data;
84
	if (packet->m != NULL) {
85 86 87 88 89 90
		freemsg(packet->m);
	}
	ms_free(packet->pd);
	ms_free(packet);
}

91 92 93 94 95
static void free_outputted_partition(void *data) {
	Vp8RtpFmtPartition *partition = (Vp8RtpFmtPartition *)data;
	ms_list_for_each(partition->packets_list, free_packet);
	ms_list_free(partition->packets_list);
	ms_free(partition);
96 97
}

98
static void free_discarded_partition(void *data) {
99
	Vp8RtpFmtPartition *partition = (Vp8RtpFmtPartition *)data;
100
	if (partition->m != NULL) {
101 102
		freemsg(partition->m);
	}
103
	ms_list_for_each(partition->packets_list, free_packet);
104 105 106 107
	ms_list_free(partition->packets_list);
	ms_free(partition);
}

108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
static void free_partition(void *data) {
	Vp8RtpFmtPartition *partition = (Vp8RtpFmtPartition *)data;
	if (partition->outputted == TRUE) {
		free_outputted_partition(partition);
	} else {
		free_discarded_partition(partition);
	}
}

static int free_outputted_frame(const void *data, const void *b) {
	Vp8RtpFmtFrame *frame = (Vp8RtpFmtFrame *)data;
	bool_t *outputted = (bool_t *)b;
	bool_t foutputted = frame->outputted;
	if (foutputted == *outputted) ms_free(frame);
	return (foutputted != *outputted);
}

static int free_discarded_frame(const void *data, const void *d) {
126
	Vp8RtpFmtFrame *frame = (Vp8RtpFmtFrame *)data;
127 128 129 130
	bool_t *discarded = (bool_t *)d;
	bool_t fdiscarded = frame->discarded;
	if (fdiscarded == *discarded) ms_free(frame);
	return (fdiscarded != *discarded);
131 132
}

133 134 135 136 137 138
static int cseq_compare(const void *d1, const void *d2) {
	Vp8RtpFmtPacket *p1 = (Vp8RtpFmtPacket *)d1;
	Vp8RtpFmtPacket *p2 = (Vp8RtpFmtPacket *)d2;
	return (p1->extended_cseq > p2->extended_cseq);
}

139
static void add_partition_to_frame(Vp8RtpFmtFrame *frame, Vp8RtpFmtPartition *partition) {
140
	Vp8RtpFmtPacket *packet;
141 142 143 144
	int nb_packets;
	int i;

	nb_packets = ms_list_size(partition->packets_list);
145 146 147 148 149 150 151 152 153 154 155 156
	if (partition->error == Vp8RtpFmtOk) {
		for (i = 0; i < nb_packets; i++) {
			packet = ms_list_nth_data(partition->packets_list, i);
			if (partition->m == NULL) {
				partition->m = packet->m;
			} else {
				concatb(partition->m, packet->m);
			}
			packet->m = NULL;
		}
		if (partition->m != NULL) {
			msgpullup(partition->m, -1);
157 158
		}

159 160 161 162 163 164 165 166 167
		frame->partitions_list = ms_list_append(frame->partitions_list, (void *)partition);
	} else {
		for (i = 0; i < nb_packets; i++) {
			packet = ms_list_nth_data(partition->packets_list, i);
			if (packet->error == Vp8RtpFmtOk) {
				packet->error = Vp8RtpFmtIncompletePartition;
			}
		}
	}
168 169
}

170 171 172 173 174
static void generate_partitions_list(Vp8RtpFmtUnpackerCtx *ctx, Vp8RtpFmtFrame *frame, MSList *packets_list) {
	Vp8RtpFmtPacket *packet = NULL;
	Vp8RtpFmtPartition *partition = NULL;
	int nb_packets = ms_list_size(packets_list);
	uint32_t last_cseq;
175 176 177
	int i;

	for (i = 0; i < nb_packets; i++) {
178 179 180
		packet = (Vp8RtpFmtPacket *)ms_list_nth_data(packets_list, i);
		if ((i > 0) && (packet->extended_cseq != (last_cseq + 1))) {
			if (partition != NULL) {
181
				/* There was a gap in the sequence numbers, the current partition is incomplete. */
182 183
				partition->packets_list = ms_list_append(partition->packets_list, (void *)packet);
				partition->error = Vp8RtpFmtIncompletePartition;
184
				frame->error = Vp8RtpFmtIncompleteFrame;
185
			}
186
		}
187 188 189
		if (packet->error == Vp8RtpFmtOk) {
			if (packet->pd->start_of_partition == TRUE) {
				if (partition != NULL) {
190
					/* The current partition is complete, and the current packet is part of a new partition. */
191
					add_partition_to_frame(frame, partition);
192
				}
193 194
				partition = ms_new0(Vp8RtpFmtPartition, 1);
				partition->packets_list = ms_list_append(partition->packets_list, (void *)packet);
195
			} else {
196
				if (partition != NULL) {
197
					/* The current packet is a part of the current partition. */
198
					partition->packets_list = ms_list_append(partition->packets_list, (void *)packet);
199 200
				} else {
					/* The current packet is not a start of partition, but a start of partition was expected. */
201 202 203
					partition = ms_new0(Vp8RtpFmtPartition, 1);
					partition->packets_list = ms_list_append(partition->packets_list, (void *)packet);
					partition->error = Vp8RtpFmtIncompletePartition;
204 205 206 207 208
					frame->error = Vp8RtpFmtIncompleteFrame;
				}
			}
		} else {
			/* Malformed packet. */
209 210
			if (partition == NULL) {
				partition = ms_new0(Vp8RtpFmtPartition, 1);
211
			}
212 213
			partition->packets_list = ms_list_append(partition->packets_list, (void *)packet);
			partition->error = Vp8RtpFmtInvalidPartition;
214
			frame->error = Vp8RtpFmtInvalidFrame;
215
		}
216 217 218 219
		if (mblk_get_marker_info(packet->m) == TRUE) {
			partition->last_partition_of_frame = TRUE;
			add_partition_to_frame(frame, partition);
			partition = NULL;
220
		}
221
		last_cseq = packet->extended_cseq;
222 223 224
	}
}

225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
static bool_t is_first_partition_present_in_frame(Vp8RtpFmtFrame *frame) {
	Vp8RtpFmtPartition *partition = ms_list_nth_data(frame->partitions_list, 0);
	Vp8RtpFmtPacket *packet = ms_list_nth_data(partition->packets_list, 0);
	if ((packet->pd->start_of_partition == TRUE) && (packet->pd->pid == 0)) {
		return TRUE;
	}
	return FALSE;
}

static void add_frame(Vp8RtpFmtUnpackerCtx *ctx, MSList **packets_list) {
	Vp8RtpFmtFrame *frame;

	if (ms_list_size(*packets_list) > 0) {
		frame = ms_new0(Vp8RtpFmtFrame, 1);
		generate_partitions_list(ctx, frame, *packets_list);
240 241 242 243 244 245 246
		if (ms_list_size(frame->partitions_list) > 0) {
			if (is_first_partition_present_in_frame(frame) == TRUE) {
				/* The first packet of the frame is really the start of the frame. */
			} else {
				frame->error = Vp8RtpFmtIncompleteFrame;
			}
			ctx->frames_list = ms_list_append(ctx->frames_list, (void *)frame);
247
		} else {
248 249 250
			/* There are no valid partitions in the frame. */
			ms_warning("VP8 frame without any valid partition.");
			ms_free(frame);
251
			ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
252
			ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
253 254
		}
	}
255 256
	ms_list_free(*packets_list);
	*packets_list = NULL;
257 258 259 260 261 262 263
}

static void generate_frames_list(Vp8RtpFmtUnpackerCtx *ctx, MSList *packets_list) {
	Vp8RtpFmtPacket *packet;
	MSList *frame_packets_list = NULL;
	int nb_packets = ms_list_size(packets_list);
	uint32_t ts;
264 265
	int i;

266 267 268 269 270 271 272 273
	for (i = 0; i < nb_packets; i++) {
		packet = ms_list_nth_data(packets_list, i);
		ts = mblk_get_timestamp_info(packet->m);

		if ((ctx->initialized_last_ts == TRUE) && (ts != ctx->last_ts)) {
			/* The current packet is from a frame different than the previous one
			* (that apparently is not complete). */
			add_frame(ctx, &frame_packets_list);
274
		}
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
		ctx->last_ts = ts;
		ctx->initialized_last_ts = TRUE;

		/* Add the current packet to the current frame. */
		frame_packets_list = ms_list_append(frame_packets_list, packet);

		if (mblk_get_marker_info(packet->m)) {
			/* The current packet is the last of the current frame. */
			add_frame(ctx, &frame_packets_list);
		}
	}
}

static bool_t is_frame_marker_present(Vp8RtpFmtFrame *frame) {
	int nb_partitions = ms_list_size(frame->partitions_list);
	Vp8RtpFmtPartition *partition = ms_list_nth_data(frame->partitions_list, nb_partitions - 1);
	return (bool_t)mblk_get_marker_info(partition->m);
}

static void output_partition(MSQueue *out, Vp8RtpFmtPartition *partition) {
	if (partition->last_partition_of_frame) {
		mblk_set_marker_info(partition->m, 1);
	}
	ms_queue_put(out, (void *)partition->m);
	partition->outputted = TRUE;
}

302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322
static void output_frame(MSQueue *out, Vp8RtpFmtFrame *frame) {
	Vp8RtpFmtPartition *partition;
	int nb_partitions = ms_list_size(frame->partitions_list);
	mblk_t *om;
	mblk_t *curm;
	int i;

	for (i = 0; i < nb_partitions; i++) {
		partition = ms_list_nth_data(frame->partitions_list, i);
		if (i == 0) {
			om = partition->m;
			curm = om;
		} else {
			curm = concatb(curm, partition->m);
		}
		partition->outputted = TRUE;
	}
	mblk_set_marker_info(om, 1);
	ms_queue_put(out, (void *)om);
}

323 324 325 326 327 328 329 330 331 332 333
static bool_t is_keyframe(Vp8RtpFmtFrame *frame) {
	Vp8RtpFmtPartition *partition;
	int nb_partitions = ms_list_size(frame->partitions_list);

	if (nb_partitions < 1) return FALSE;
	partition = (Vp8RtpFmtPartition *)ms_list_nth_data(frame->partitions_list, 0);
	if (partition->m->b_rptr[0] & 0x01) return FALSE;

	return TRUE;
}

334 335 336 337 338 339 340 341 342 343 344
static void output_valid_partitions(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *out) {
	Vp8RtpFmtPartition *partition = NULL;
	Vp8RtpFmtFrame *frame;
	int nb_frames = ms_list_size(ctx->frames_list);
	int nb_partitions;
	int i;
	int j;

	for (i = 0; i < nb_frames; i++) {
		frame = ms_list_nth_data(ctx->frames_list, i);
		if (frame->error == Vp8RtpFmtOk) {
345 346 347 348 349 350 351 352 353 354 355 356 357 358
			if (is_keyframe(frame) == TRUE) {
				ctx->valid_keyframe_received = TRUE;
			}
			if (ctx->valid_keyframe_received == TRUE) {
				/* Output the complete valid frame if the first keyframe has been received. */
				if (ctx->output_partitions == TRUE) {
					nb_partitions = ms_list_size(frame->partitions_list);
					for (j = 0; j < nb_partitions; j++) {
						partition = ms_list_nth_data(frame->partitions_list, j);
						output_partition(out, partition);
					}
				} else {
					/* Output the full frame in one mblk_t. */
					output_frame(out, frame);
359
				}
360
				frame->outputted = TRUE;
361
			} else {
362
				/* Drop frames until the first keyframe is successfully received. */
363
				ms_warning("VP8 frame dropped because keyframe has not been received yet.");
364
				frame->discarded = TRUE;
365 366
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
367
			}
368 369
		} else if (is_frame_marker_present(frame) == TRUE) {
			if (is_first_partition_present_in_frame(frame) == TRUE) {
370 371 372 373 374 375 376 377 378 379
				if (ctx->output_partitions == TRUE) {
					/* Output the valid partitions of the frame. */
					nb_partitions = ms_list_size(frame->partitions_list);
					for (i = 0; i < nb_partitions; i++) {
						partition = ms_list_nth_data(frame->partitions_list, i);
						if (partition->error == Vp8RtpFmtOk) {
							if (i == (nb_partitions - 1)) {
								partition->last_partition_of_frame = TRUE;
							}
							output_partition(out, partition);
380 381
						}
					}
382 383 384
					frame->outputted = TRUE;
				} else {
					/* Drop the frame for which some partitions are missing/invalid. */
385
					ms_warning("VP8 frame with some partitions missing/invalid.");
386
					frame->discarded = TRUE;
387
				}
388
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
389
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
390 391
			} else {
				/* Drop the frame for which the first partition is missing. */
392
				ms_warning("VP8 frame without first partition.");
393
				frame->discarded = TRUE;
394
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
395
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
396 397 398 399
			}
		} else {
			/* The last packet of the frame has not been received.
			 * Wait for the next iteration of the filter to see if we have it then. */
400
			ms_warning("VP8 frame without last packet.");
401 402
			// TODO: Try to get the missing packets at the next iteration of the filter.
			frame->discarded = TRUE;
403
			ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
404
			ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
405 406 407 408
		}
	}
}

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
static void free_partitions_of_outputted_frames(void *data) {
	Vp8RtpFmtFrame *frame = (Vp8RtpFmtFrame *)data;
	if (frame->outputted == TRUE) {
		ms_list_for_each(frame->partitions_list, free_partition);
		ms_list_free(frame->partitions_list);
	}
}

static void free_partitions_of_discarded_frames(void *data) {
	Vp8RtpFmtFrame *frame = (Vp8RtpFmtFrame *)data;
	if (frame->discarded == TRUE) {
		ms_list_for_each(frame->partitions_list, free_partition);
		ms_list_free(frame->partitions_list);
	}
}

static void clean_outputted_partitions(Vp8RtpFmtUnpackerCtx *ctx) {
	bool_t outputted = TRUE;
	ms_list_for_each(ctx->frames_list, free_partitions_of_outputted_frames);
	ctx->frames_list = ms_list_remove_custom(ctx->frames_list, free_outputted_frame, &outputted);
}

static void clean_discarded_partitions(Vp8RtpFmtUnpackerCtx *ctx) {
	bool_t discarded = TRUE;
	ms_list_for_each(ctx->frames_list, free_partitions_of_discarded_frames);
	ctx->frames_list = ms_list_remove_custom(ctx->frames_list, free_discarded_frame, &discarded);
}

437 438
static Vp8RtpFmtErrorCode parse_payload_descriptor(Vp8RtpFmtPacket *packet) {
	uint8_t *h = packet->m->b_rptr;
439
	Vp8RtpFmtPayloadDescriptor *pd = packet->pd;
440 441 442 443
	unsigned int packet_size = packet->m->b_wptr - packet->m->b_rptr;
	uint8_t offset = 0;

	if (packet_size == 0) return Vp8RtpFmtInvalidPayloadDescriptor;
444

445
	memset(pd, 0, sizeof(Vp8RtpFmtPayloadDescriptor));
446 447

	/* Parse mandatory first octet of payload descriptor. */
448 449 450 451 452 453
	if (h[offset] & (1 << 7)) pd->extended_control_bits_present = TRUE;
	if (h[offset] & (1 << 5)) pd->non_reference_frame = TRUE;
	if (h[offset] & (1 << 4)) pd->start_of_partition = TRUE;
	pd->pid = (h[offset] & 0x07);
	offset++;
	if (offset >= packet_size) return Vp8RtpFmtInvalidPayloadDescriptor;
454 455
	/* Parse the first extension octet if needed. */
	if (pd->extended_control_bits_present == TRUE) {
456 457 458 459
		if (h[offset] & (1 << 7)) pd->pictureid_present = TRUE;
		if (h[offset] & (1 << 6)) pd->tl0picidx_present = TRUE;
		if (h[offset] & (1 << 5)) pd->tid_present = TRUE;
		if (h[offset] & (1 << 4)) pd->keyidx_present = TRUE;
460 461 462 463
		if ((pd->tl0picidx_present == TRUE) && (pd->tid_present != TRUE)) {
			/* Invalid payload descriptor. */
			return Vp8RtpFmtInvalidPayloadDescriptor;
		}
464 465
		offset++;
		if (offset >= packet_size) return Vp8RtpFmtInvalidPayloadDescriptor;
466 467 468
	}
	/* Parse the pictureID if needed. */
	if (pd->pictureid_present == TRUE) {
469
		if (h[offset] & (1 << 7)) {
470
			/* The pictureID is 16 bits long. */
471 472 473
			if ((offset + 1) >= packet_size) return Vp8RtpFmtInvalidPayloadDescriptor;
			pd->pictureid = (h[offset] << 8) | h[offset + 1];
			offset += 2;
474 475
		} else {
			/* The pictureId is 8 bits long. */
476 477
			pd->pictureid = h[offset];
			offset++;
478
		}
479
		if (offset >= packet_size) return Vp8RtpFmtInvalidPayloadDescriptor;
480 481 482
	}
	/* Parse the tl0picidx if needed. */
	if (pd->tl0picidx_present == TRUE) {
483 484 485
		pd->tl0picidx = h[offset];
		offset++;
		if (offset >= packet_size) return Vp8RtpFmtInvalidPayloadDescriptor;
486 487 488
	}
	/* Parse the tid and/or keyidx if needed. */
	if (pd->tid_present == TRUE) {
489 490
		pd->tid = (h[offset] & 0xC0) >> 6;
		if (h[offset] & (1 << 5)) pd->layer_sync = TRUE;
491 492
	}
	if (pd->keyidx_present == TRUE) {
493
		pd->keyidx = (h[offset] & 0x1F);
494 495
	}
	if ((pd->tid_present == TRUE) || (pd->keyidx_present == TRUE)) {
496 497
		offset++;
		if (offset >= packet_size) return Vp8RtpFmtInvalidPayloadDescriptor;
498 499
	}

500
	packet->m->b_rptr = &h[offset];
501 502 503 504
	return Vp8RtpFmtOk;
}


505
void vp8rtpfmt_unpacker_init(Vp8RtpFmtUnpackerCtx *ctx, MSFilter *f, bool_t output_partitions) {
506
	ctx->filter = f;
507
	ctx->frames_list = NULL;
508
	ms_queue_init(&ctx->output_queue);
509 510
	ctx->output_partitions = output_partitions;
	ctx->valid_keyframe_received = FALSE;
511
	ctx->initialized_last_ts = FALSE;
512 513 514
	ctx->initialized_ref_cseq = FALSE;
}

515
void vp8rtpfmt_unpacker_uninit(Vp8RtpFmtUnpackerCtx *ctx) {
516
	ms_list_free(ctx->frames_list);
517
	ms_queue_flush(&ctx->output_queue);
518 519
}

520 521
void vp8rtpfmt_unpacker_process(Vp8RtpFmtUnpackerCtx *ctx, MSQueue *inout) {
	MSList *packets_list = NULL;
522 523 524 525
	Vp8RtpFmtPacket *packet;
	mblk_t *m;

#ifdef VP8RTPFMT_DEBUG
526
	ms_message("vp8rtpfmt_unpacker_process:");
527
#endif
528
	while ((m = ms_queue_get(inout)) != NULL) {
529 530
		packet = ms_new(Vp8RtpFmtPacket, 1);
		packet->m = m;
531 532
		packet->extended_cseq = vp8rtpfmt_unpacker_calc_extended_cseq(ctx, mblk_get_cseq(m));
		packet->pd = ms_new0(Vp8RtpFmtPayloadDescriptor, 1);
533 534 535

		if (m->b_cont) msgpullup(m, -1);
		packet->error = parse_payload_descriptor(packet);
536
		packets_list = ms_list_insert_sorted(packets_list, (void *)packet, cseq_compare);
537 538
	}

539 540
	generate_frames_list(ctx, packets_list);
	ms_list_free(packets_list);
541
#ifdef VP8RTPFMT_DEBUG
542
	ms_list_for_each(ctx->frames_list, print_frame);
543
#endif /* VP8RTPFMT_DEBUG */
544 545 546
	output_valid_partitions(ctx, inout);
	clean_outputted_partitions(ctx);
	clean_discarded_partitions(ctx);
547

548 549 550 551
	if (ms_list_size(ctx->frames_list) == 0) {
		ms_list_free(ctx->frames_list);
		ctx->frames_list = NULL;
	} else {
552
		ms_message("VP8 frames are remaining for next iteration of the filter.");
553
	}
554 555
}

556
uint32_t vp8rtpfmt_unpacker_calc_extended_cseq(Vp8RtpFmtUnpackerCtx *ctx, uint16_t cseq) {
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
	uint32_t extended_cseq;
	uint32_t cseq_a;
	uint32_t cseq_b;
	uint32_t diff_a;
	uint32_t diff_b;

	if (ctx->initialized_ref_cseq != TRUE) {
		ctx->ref_cseq = cseq | 0x80000000;
		ctx->initialized_ref_cseq = TRUE;
		extended_cseq = ctx->ref_cseq;
	} else {
		cseq_a = cseq | (ctx->ref_cseq & 0xFFFF0000);
		if (ctx->ref_cseq < cseq_a) {
			cseq_b = cseq_a - 0x00010000;
			diff_a = cseq_a - ctx->ref_cseq;
			diff_b = ctx->ref_cseq - cseq_b;
		} else {
			cseq_b = cseq_a + 0x00010000;
			diff_a = ctx->ref_cseq - cseq_a;
			diff_b = cseq_b - ctx->ref_cseq;
		}
		if (diff_a < diff_b) {
			extended_cseq = cseq_a;
		} else {
			extended_cseq = cseq_b;
		}
		ctx->ref_cseq = extended_cseq;
	}

	return extended_cseq;
}
588 589 590 591 592 593



static void packer_process_frame_part(void *p, void *c) {
	Vp8RtpFmtPacket *packet = (Vp8RtpFmtPacket *)p;
	Vp8RtpFmtPackerCtx *ctx = (Vp8RtpFmtPackerCtx *)c;
Ghislain MARY's avatar
Ghislain MARY committed
594 595
	mblk_t *pdm = NULL;
	mblk_t *dm = NULL;
596 597 598 599
	uint8_t *rptr;
	uint8_t pdsize = 1;
	int max_size = ms_get_payload_max_size();
	int dlen;
600
	bool_t marker_info = mblk_get_marker_info(packet->m);
601 602 603 604 605 606 607 608 609 610

	/* Calculate the payload descriptor size. */
	if (packet->pd->extended_control_bits_present == TRUE) pdsize++;
	if (packet->pd->pictureid_present == TRUE) {
		pdsize++;
		if (packet->pd->pictureid & 0x8000) pdsize++;
	}
	if (packet->pd->tl0picidx_present == TRUE) pdsize++;
	if ((packet->pd->tid_present == TRUE) || (packet->pd->keyidx_present == TRUE)) pdsize++;

Ghislain MARY's avatar
Ghislain MARY committed
611
	mblk_set_marker_info(packet->m, FALSE);
612 613 614 615 616
	for (rptr = packet->m->b_rptr; rptr < packet->m->b_wptr;) {
		/* Allocate the payload descriptor. */
		pdm = allocb(pdsize, 0);
		memset(pdm->b_wptr, 0, pdsize);
		mblk_set_timestamp_info(pdm, mblk_get_timestamp_info(packet->m));
617
		mblk_set_marker_info(pdm, FALSE);
618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666
		/* Fill the mandatory octet of the payload descriptor. */
		if (packet->pd->extended_control_bits_present == TRUE) *pdm->b_wptr |= (1 << 7);
		if (packet->pd->non_reference_frame == TRUE) *pdm->b_wptr |= (1 << 5);
		if (packet->pd->start_of_partition == TRUE) {
			if (packet->m->b_rptr == rptr) *pdm->b_wptr |= (1 << 4);
		}
		*pdm->b_wptr |= (packet->pd->pid & 0x07);
		pdm->b_wptr++;
		/* Fill the extension bit field octet of the payload descriptor. */
		if (packet->pd->extended_control_bits_present == TRUE) {
			if (packet->pd->pictureid_present == TRUE) *pdm->b_wptr |= (1 << 7);
			if (packet->pd->tl0picidx_present == TRUE) *pdm->b_wptr |= (1 << 6);
			if (packet->pd->tid_present == TRUE) *pdm->b_wptr |= (1 << 5);
			if (packet->pd->keyidx_present == TRUE) *pdm->b_wptr |= (1 << 4);
			pdm->b_wptr++;
		}
		/* Fill the pictureID field of the payload descriptor. */
		if (packet->pd->pictureid_present == TRUE) {
			if (packet->pd->pictureid & 0x8000) {
				*pdm->b_wptr |= ((packet->pd->pictureid >> 8) & 0xFF);
				pdm->b_wptr++;
			}
			*pdm->b_wptr |= (packet->pd->pictureid & 0xFF);
			pdm->b_wptr++;
		}
		/* Fill the tl0picidx octet of the payload descriptor. */
		if (packet->pd->tl0picidx_present == TRUE) {
			*pdm->b_wptr = packet->pd->tl0picidx;
			pdm->b_wptr++;
		}
		if ((packet->pd->tid_present == TRUE) || (packet->pd->keyidx_present == TRUE)) {
			if (packet->pd->tid_present == TRUE) {
				*pdm->b_wptr |= (packet->pd->tid & 0xC0);
				if (packet->pd->layer_sync == TRUE) *pdm->b_wptr |= (1 << 5);
			}
			if (packet->pd->keyidx_present == TRUE) {
				*pdm->b_wptr |= (packet->pd->keyidx & 0x1F);
			}
			pdm->b_wptr++;
		}

		dlen = MIN((max_size - pdsize), (packet->m->b_wptr - rptr));
		dm = dupb(packet->m);
		dm->b_rptr = rptr;
		dm->b_wptr = rptr + dlen;
		dm->b_wptr = dm->b_rptr + dlen;
		pdm->b_cont = dm;
		rptr += dlen;

667
		ms_queue_put(ctx->output_queue, pdm);
668 669
	}

670
	/* Set marker bit on last packet if required. */
Ghislain MARY's avatar
Ghislain MARY committed
671 672
	if (pdm != NULL) mblk_set_marker_info(pdm, marker_info);
	if (dm != NULL) mblk_set_marker_info(dm, marker_info);
673

674 675 676 677 678
	freeb(packet->m);
	packet->m = NULL;
}


679
void vp8rtpfmt_packer_init(Vp8RtpFmtPackerCtx *ctx) {
680 681 682 683 684
}

void vp8rtpfmt_packer_uninit(Vp8RtpFmtPackerCtx *ctx) {
}

685 686
void vp8rtpfmt_packer_process(Vp8RtpFmtPackerCtx *ctx, MSList *in, MSQueue *out) {
	ctx->output_queue = out;
687 688 689 690
	ms_list_for_each2(in, packer_process_frame_part, ctx);
	ms_list_for_each(in, free_packet);
	ms_list_free(in);
}