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
static void output_frame(MSQueue *out, Vp8RtpFmtFrame *frame) {
	Vp8RtpFmtPartition *partition;
	int nb_partitions = ms_list_size(frame->partitions_list);
305
	mblk_t *om = NULL;
306 307 308 309 310 311 312 313 314 315 316 317 318
	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;
	}
319 320 321 322
	if (om != NULL) {
		mblk_set_marker_info(om, 1);
		ms_queue_put(out, (void *)om);
	}
323 324
}

325 326 327 328 329 330 331 332 333 334 335
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;
}

336 337 338 339 340 341 342 343 344 345 346
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) {
347 348 349 350 351 352 353 354 355 356 357 358 359 360
			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);
361
				}
362
				frame->outputted = TRUE;
363
			} else {
364
				/* Drop frames until the first keyframe is successfully received. */
365
				ms_warning("VP8 frame dropped because keyframe has not been received yet.");
366
				frame->discarded = TRUE;
367 368
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
369
			}
370 371
		} else if (is_frame_marker_present(frame) == TRUE) {
			if (is_first_partition_present_in_frame(frame) == TRUE) {
372 373 374 375 376 377 378 379 380 381
				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);
382 383
						}
					}
384 385 386
					frame->outputted = TRUE;
				} else {
					/* Drop the frame for which some partitions are missing/invalid. */
387
					ms_warning("VP8 frame with some partitions missing/invalid.");
388
					frame->discarded = TRUE;
389
				}
390
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
391
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
392 393
			} else {
				/* Drop the frame for which the first partition is missing. */
394
				ms_warning("VP8 frame without first partition.");
395
				frame->discarded = TRUE;
396
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
397
				ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
398 399 400 401
			}
		} 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. */
402
			ms_warning("VP8 frame without last packet.");
403 404
			// TODO: Try to get the missing packets at the next iteration of the filter.
			frame->discarded = TRUE;
405
			ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_DECODING_ERRORS);
406
			ms_filter_notify_no_arg(ctx->filter, MS_VIDEO_DECODER_SEND_PLI);
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 437 438
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);
}

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

	if (packet_size == 0) return Vp8RtpFmtInvalidPayloadDescriptor;
446

447
	memset(pd, 0, sizeof(Vp8RtpFmtPayloadDescriptor));
448 449

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

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


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

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

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

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

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

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

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

558
uint32_t vp8rtpfmt_unpacker_calc_extended_cseq(Vp8RtpFmtUnpackerCtx *ctx, uint16_t cseq) {
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 588 589
	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;
}
590 591 592 593 594 595



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
596 597
	mblk_t *pdm = NULL;
	mblk_t *dm = NULL;
598 599 600 601
	uint8_t *rptr;
	uint8_t pdsize = 1;
	int max_size = ms_get_payload_max_size();
	int dlen;
602
	bool_t marker_info = mblk_get_marker_info(packet->m);
603 604 605 606 607 608 609 610 611 612

	/* 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
613
	mblk_set_marker_info(packet->m, FALSE);
614 615 616 617 618
	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));
619
		mblk_set_marker_info(pdm, FALSE);
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 667 668
		/* 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;

669
		ms_queue_put(ctx->output_queue, pdm);
670 671
	}

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

676 677 678 679 680
	freeb(packet->m);
	packet->m = NULL;
}


681
void vp8rtpfmt_packer_init(Vp8RtpFmtPackerCtx *ctx) {
682 683 684 685 686
}

void vp8rtpfmt_packer_uninit(Vp8RtpFmtPackerCtx *ctx) {
}

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