mkv.c 79.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)

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.
*/

20 21 22 23
#define bool_t ms_bool_t
#include "mediastreamer2/msfilter.h"
#include "mediastreamer2/msvideo.h"
#include "mediastreamer2/rfc3984.h"
24
#include "mediastreamer2/msticker.h"
25
#include "../audiofilters/waveheader.h"
26
#include "mediastreamer2/formats.h"
27
#include "mkv_reader.h"
28 29 30 31 32 33 34 35 36
#undef bool_t

#define bool_t matroska_bool_t
#include <matroska/matroska.h>
#include <matroska/matroska_sem.h>
#undef bool_t

#define bool_t ambigous use ms_bool_t or matroska_bool_t

37 38
static int recorder_close(MSFilter *f, void *arg);

39 40 41
/*********************************************************************************************
 * Module interface                                                                          *
 *********************************************************************************************/
François Grisez's avatar
François Grisez committed
42 43
typedef void *(*ModuleNewFunc)();
typedef void (*ModuleFreeFunc)(void *obj);
44
typedef void (*ModuleSetFunc)(void *obj, const MSFmtDescriptor *fmt);
45
typedef void (*ModulePreProFunc)(void *obj, MSQueue *input, MSQueue *output);
46 47
typedef mblk_t *(*ModuleProFunc)(void *obj, mblk_t *buffer, ms_bool_t *isKeyFrame, uint8_t **codecPrivateData, size_t *codecPrivateSize);
typedef void (*ModuleReverseFunc)(void *obj, mblk_t *input, MSQueue *output, ms_bool_t isFirstFrame, const uint8_t *codecPrivateData, size_t codecPrivateSize);
48
typedef void (*ModulePrivateDataFunc)(const void *obj, uint8_t **data, size_t *data_size);
49
typedef void (*ModulePrivateDataLoadFunc)(void *obj, const uint8_t *data, size_t size);
50
typedef ms_bool_t (*ModuleIsKeyFrameFunc)(const mblk_t *frame);
51

François Grisez's avatar
François Grisez committed
52
typedef struct {
53 54
	const char *rfcName;
	const char *codecId;
François Grisez's avatar
François Grisez committed
55 56
	ModuleNewFunc new_module;
	ModuleFreeFunc free_module;
57 58 59
	ModuleSetFunc set;
	ModulePreProFunc preprocess;
	ModuleProFunc process;
60
	ModuleReverseFunc reverse;
61 62 63
	ModulePrivateDataFunc get_private_data;
	ModulePrivateDataLoadFunc load_private_data;
	ModuleIsKeyFrameFunc is_key_frame;
64 65 66 67 68 69
} ModuleDesc;

/*********************************************************************************************
 * h264 module                                                                               *
 *********************************************************************************************/
/* H264Private */
François Grisez's avatar
François Grisez committed
70
typedef struct {
71 72 73 74 75
	uint8_t profile;
	uint8_t level;
	uint8_t NALULenghtSizeMinusOne;
	MSList *sps_list;
	MSList *pps_list;
76 77
} H264Private;

78 79 80 81 82 83
static void _ms_list_append_copy(const mblk_t *buffer, MSList **list) {
	*list = ms_list_append(*list, copymsg(buffer));
}

static void H264Private_init(H264Private *obj, const MSList *spsList, const MSList *ppsList) {
	memset(obj, 0, sizeof(H264Private));
84
	obj->NALULenghtSizeMinusOne = 0xFF;
85 86 87 88 89 90 91
	ms_list_for_each2(spsList, (MSIterate2Func)_ms_list_append_copy, &obj->sps_list);
	ms_list_for_each2(ppsList, (MSIterate2Func)_ms_list_append_copy, &obj->pps_list);
	if(obj->sps_list != NULL) {
		const mblk_t *firstSPS = (const mblk_t *)ms_list_nth_data(obj->sps_list, 0);
		obj->profile = firstSPS->b_rptr[1];
		obj->level = firstSPS->b_rptr[3];
	}
92 93
}

94 95 96
static void H264Private_uninit(H264Private *obj) {
	if(obj->sps_list != NULL) ms_list_free_with_data(obj->sps_list,(void (*)(void *))freemsg);
	if(obj->pps_list != NULL) ms_list_free_with_data(obj->pps_list,(void (*)(void *))freemsg);
97 98
}

99
static H264Private *H264Private_new(const MSList *spsList, const MSList *ppsList) {
100
	H264Private *obj = (H264Private *)ms_new0(H264Private, 1);
101 102
	H264Private_init(obj, spsList, ppsList);
	return obj;
103 104
}

105 106 107
static void H264Private_free(H264Private *obj) {
	H264Private_uninit(obj);
	ms_free(obj);
108 109
}

110 111
static inline const MSList *H264Private_getSPS(const H264Private *obj) {
	return obj->sps_list;
112 113
}

114 115
static inline const MSList *H264Private_getPPS(const H264Private *obj) {
	return obj->pps_list;
116 117
}

François Grisez's avatar
François Grisez committed
118
static void H264Private_serialize(const H264Private *obj, uint8_t **data, size_t *size) {
119 120 121 122
	uint8_t nbSPS, nbPPS;
	MSList *it = NULL;
	uint8_t *result = NULL;
	int i;
123

124 125
	nbSPS = ms_list_size(obj->sps_list);
	nbPPS = ms_list_size(obj->pps_list);
126

127
	*size = 7;
128 129
	*size += (nbSPS + nbPPS) * 2;

François Grisez's avatar
François Grisez committed
130
	for(it=obj->sps_list;it!=NULL;it=it->next) {
131 132 133
		mblk_t *buff = (mblk_t*)(it->data);
		*size += msgdsize(buff);
	}
François Grisez's avatar
François Grisez committed
134
	for(it=obj->pps_list;it!=NULL;it=it->next) {
135 136 137 138
		mblk_t *buff = (mblk_t*)(it->data);
		*size += msgdsize(buff);
	}

139
	result = (uint8_t *)ms_new0(uint8_t, *size);
140 141 142 143 144 145
	result[0] = 0x01;
	result[1] = obj->profile;
	result[3] = obj->level;
	result[4] = obj->NALULenghtSizeMinusOne;
	result[5] = nbSPS & 0x1F;

146
	i=6;
François Grisez's avatar
François Grisez committed
147
	for(it=obj->sps_list; it!=NULL; it=it->next) {
148 149 150 151 152 153 154 155 156 157 158 159
		mblk_t *buff = (mblk_t*)(it->data);
		size_t buff_size = msgdsize(buff);
		uint16_t buff_size_be = htons(buff_size);
		memcpy(&result[i], &buff_size_be, sizeof(buff_size_be));
		i+=sizeof(buff_size_be);
		memcpy(&result[i], buff->b_rptr, buff_size);
		i += buff_size;
	}

	result[i] = nbPPS;
	i++;

François Grisez's avatar
François Grisez committed
160
	for(it=obj->pps_list; it!=NULL; it=it->next) {
161 162 163 164 165 166 167 168 169
		mblk_t *buff = (mblk_t*)(it->data);
		int buff_size = msgdsize(buff);
		uint16_t buff_size_be = htons(buff_size);
		memcpy(&result[i], &buff_size_be, sizeof(buff_size_be));
		i+=sizeof(buff_size_be);
		memcpy(&result[i], buff->b_rptr, buff_size);
		i += buff_size;
	}
	*data = result;
170 171
}

François Grisez's avatar
François Grisez committed
172
static void H264Private_load(H264Private *obj, const uint8_t *data) {
173 174 175 176
	int i, N;
	const uint8_t *r_ptr = NULL;
	uint16_t nalu_size;
	mblk_t *nalu = NULL;
177

178 179
	H264Private_uninit(obj);
	H264Private_init(obj, NULL, NULL);
180

181 182 183
	N = data[5] & 0x1F;
	r_ptr = data + 6;
	for(i=0;i<N;i++) {
184 185
		memcpy(&nalu_size, r_ptr, sizeof(uint16_t)); r_ptr += sizeof(uint16_t);
		nalu_size = ntohs(nalu_size);
186
		nalu = allocb(nalu_size, 0);
187 188 189 190
		memcpy(nalu->b_wptr, r_ptr, nalu_size); nalu->b_wptr += nalu_size; r_ptr += nalu_size;
		obj->sps_list = ms_list_append(obj->sps_list, nalu);
	}

191 192
	N = *r_ptr; r_ptr += 1;
	for(i=0;i<N;i++) {
193 194
		memcpy(&nalu_size, r_ptr, sizeof(uint16_t)); r_ptr += sizeof(uint16_t);
		nalu_size = ntohs(nalu_size);
195
		nalu = allocb(nalu_size, 0);
196 197 198
		memcpy(nalu->b_wptr, r_ptr, nalu_size); nalu->b_wptr += nalu_size; r_ptr += nalu_size;
		obj->pps_list = ms_list_append(obj->pps_list, nalu);
	}
199

200 201 202 203 204
	if(obj->sps_list != NULL) {
		const mblk_t *firstSPS = (const mblk_t *)ms_list_nth_data(obj->sps_list, 0);
		obj->profile = firstSPS->b_rptr[1];
		obj->level = firstSPS->b_rptr[3];
	}
205 206 207
}

/* h264 module */
208
typedef struct {
209
	Rfc3984Context rfc3984Context;
210
	H264Private *codecPrivate;
211 212
} H264Module;

213 214
static void *h264_module_new() {
	H264Module *mod = ms_new0(H264Module, 1);
215
	rfc3984_init(&mod->rfc3984Context);
216
	rfc3984_set_mode(&mod->rfc3984Context,1);
François Grisez's avatar
François Grisez committed
217
	return mod;
218 219
}

220
static void h264_module_free(void *data) {
221 222
	H264Module *obj = (H264Module *)data;
	rfc3984_uninit(&obj->rfc3984Context);
223 224 225
	if(obj->codecPrivate != NULL) {
		H264Private_free(obj->codecPrivate);
	}
226
	ms_free(obj);
227 228
}

229
static void h264_module_preprocessing(void *data, MSQueue *input, MSQueue *output) {
230 231
	H264Module *obj = (H264Module *)data;
	MSQueue queue;
232
	mblk_t *inputBuffer = NULL;
233 234

	ms_queue_init(&queue);
235
	while((inputBuffer = ms_queue_get(input)) != NULL) {
236
		rfc3984_unpack(&obj->rfc3984Context, inputBuffer, &queue);
237
		if(!ms_queue_empty(&queue)) {
238 239
			mblk_t *frame = ms_queue_get(&queue);
			mblk_t *end = frame;
240
			while(!ms_queue_empty(&queue)) {
241 242 243 244 245
				end = concatb(end, ms_queue_get(&queue));
			}
			ms_queue_put(output, frame);
		}
	}
246 247
}

248
static inline int h264_nalu_type(const mblk_t *nalu) {
249
	return (nalu->b_rptr[0]) & ((1<<5)-1);
250 251
}

252
static ms_bool_t h264_is_key_frame(const mblk_t *frame) {
253
	const mblk_t *curNalu = NULL;
254 255
	for(curNalu = frame; curNalu != NULL && h264_nalu_type(curNalu) != 5; curNalu = curNalu->b_cont);
	return curNalu != NULL;
256 257
}

258 259
static void nalus_to_frame(mblk_t *buffer, mblk_t **frame, MSList **spsList, MSList **ppsList, ms_bool_t *isKeyFrame) {
	mblk_t *curNalu = NULL;
260
	uint32_t timecode = mblk_get_timestamp_info(buffer);
261 262
	*frame = NULL;
	*isKeyFrame = FALSE;
263
	
264

265
	for(curNalu = buffer; curNalu != NULL;) {
266
		mblk_t *buff = curNalu;
267 268
		int type = h264_nalu_type(buff);
		
269 270
		curNalu = curNalu->b_cont;
		buff->b_cont = NULL;
271
		switch(type) {
272
		case 7:
273
			*spsList = ms_list_append(*spsList, buff);
274 275 276
			break;

		case 8:
277
			*ppsList = ms_list_append(*ppsList, buff);
278 279 280
			break;

		default:
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297
			{
				uint32_t bufferSize = htonl(msgdsize(buff));
				mblk_t *size = allocb(4, 0);
				
				if(type == 5) {
					*isKeyFrame = TRUE;
				}
				memcpy(size->b_wptr, &bufferSize, sizeof(bufferSize));
				size->b_wptr = size->b_wptr + sizeof(bufferSize);
				concatb(size, buff);
				buff = size;

				if(*frame == NULL) {
					*frame = buff;
				} else {
					concatb(*frame, buff);
				}
298
			}
299 300 301
		}
	}

302
	if(*frame != NULL) {
303 304 305
		msgpullup(*frame, -1);
		mblk_set_timestamp_info(*frame, timecode);
	}
306 307
}

308
static mblk_t *h264_module_processing(void *data, mblk_t *nalus, ms_bool_t *isKeyFrame, uint8_t **codecPrivateData, size_t *codecPrivateSize) {
309
	H264Module *obj = (H264Module *)data;
310 311 312 313 314 315 316 317 318 319 320 321 322
	mblk_t *frame = NULL;
	MSList *spsList = NULL, *ppsList = NULL;
	nalus_to_frame(nalus, &frame, &spsList, &ppsList, isKeyFrame);
	if(spsList != NULL || ppsList != NULL) {
		H264Private *codecPrivateStruct = H264Private_new(spsList, ppsList);
		if(obj->codecPrivate == NULL) {
			obj->codecPrivate = codecPrivateStruct;
		} else {
			H264Private_serialize(codecPrivateStruct, codecPrivateData, codecPrivateSize);
			H264Private_free(codecPrivateStruct);
		}
		if(spsList != NULL) ms_list_free_with_data(spsList, (void (*)(void *))freemsg);
		if(ppsList != NULL) ms_list_free_with_data(ppsList, (void (*)(void *))freemsg);
323 324
	}
	return frame;
325 326
}

327 328
static void h264_module_reverse(void *data, mblk_t *input, MSQueue *output, ms_bool_t isFirstFrame, const uint8_t *codecPrivateData, size_t codecPrivateSize) {
	mblk_t *buffer = NULL, *bufferFrag = NULL;
329 330
	H264Module *obj = (H264Module *)data;
	MSQueue queue;
331 332 333
	const MSList *it = NULL;
	H264Private *codecPrivate = NULL, *selectedCodecPrivate = NULL;

334 335 336 337 338 339 340 341 342 343 344 345 346 347
	ms_queue_init(&queue);
	while(input->b_rptr != input->b_wptr) {
		uint32_t naluSize;
		mblk_t *nalu;
		memcpy(&naluSize, input->b_rptr, sizeof(uint32_t)); input->b_rptr += sizeof(uint32_t);
		naluSize = ntohl(naluSize);
		nalu = allocb(naluSize, 0);
		memcpy(nalu->b_wptr, input->b_rptr, naluSize); nalu->b_wptr += naluSize; input->b_rptr += naluSize;
		if(buffer == NULL) {
			buffer = nalu;
		} else {
			concatb(buffer, nalu);
		}
	}
348 349 350 351 352 353 354 355 356 357 358
	if(isFirstFrame) {
		selectedCodecPrivate = obj->codecPrivate;
	} else if(codecPrivateData != NULL) {
		codecPrivate = H264Private_new(NULL, NULL);
		H264Private_load(codecPrivate, codecPrivateData);
		selectedCodecPrivate = codecPrivate;
	}
	if(selectedCodecPrivate != NULL) {
		for(it = H264Private_getSPS(selectedCodecPrivate); it != NULL; it = it->next) {
			mblk_t *sps = copymsg((mblk_t *)it->data);
			ms_queue_put(&queue, sps);
359
			ms_message("MKVPlayer: send SPS");
360 361 362 363
		}
		for(it = H264Private_getPPS(selectedCodecPrivate); it != NULL; it = it->next) {
			mblk_t *pps = copymsg((mblk_t *)it->data);
			ms_queue_put(&queue, pps);
364
			ms_message("MKVPlayer: send PPS");
365
		}
366
	}
367 368 369

	if(codecPrivate != NULL) H264Private_free(codecPrivate);

370 371 372 373 374 375 376
	for(bufferFrag = buffer; bufferFrag != NULL;) {
		mblk_t *curBuff = bufferFrag;
		bufferFrag = bufferFrag->b_cont;
		curBuff->b_cont = NULL;
		ms_queue_put(&queue, curBuff);
	}
	rfc3984_pack(&obj->rfc3984Context, &queue, output, mblk_get_timestamp_info(input));
377
	freemsg(input);
378 379 380
}

static void h264_module_get_private_data(const void *o, uint8_t **data, size_t *data_size) {
381
	const H264Module *obj = (const H264Module *)o;
382
	H264Private_serialize(obj->codecPrivate, data, data_size);
383 384
}

385
static void h264_module_load_private_data(void *o, const uint8_t *data, size_t size) {
386
	H264Module *obj = (H264Module *)o;
387 388
	obj->codecPrivate = H264Private_new(NULL, NULL);
	H264Private_load(obj->codecPrivate, data);
389 390
}

391
/* h264 module description */
392
#ifdef _MSC_VER
393
static const ModuleDesc h264_module_desc = {
394 395
	"H264",
	"V_MPEG4/ISO/AVC",
François Grisez's avatar
François Grisez committed
396 397
	h264_module_new,
	h264_module_free,
398 399 400
	NULL,
	h264_module_preprocessing,
	h264_module_processing,
401
	h264_module_reverse,
402 403 404
	h264_module_get_private_data,
	h264_module_load_private_data,
	h264_is_key_frame
405
};
406
#else
407
static const ModuleDesc h264_module_desc = {
408 409 410 411 412 413 414 415 416 417 418 419 420
	.rfcName = "H264",
	.codecId = "V_MPEG4/ISO/AVC",
	.new_module = h264_module_new,
	.free_module = h264_module_free,
	.set = NULL,
	.preprocess = h264_module_preprocessing,
	.process = h264_module_processing,
	.reverse = h264_module_reverse,
	.get_private_data = h264_module_get_private_data,
	.load_private_data = h264_module_load_private_data,
	.is_key_frame = h264_is_key_frame
};
#endif
421 422 423 424 425

/*********************************************************************************************
 * µLaw module                                                                               *
 *********************************************************************************************/
/* WavPrivate */
François Grisez's avatar
François Grisez committed
426
typedef struct {
427 428 429 430 431 432 433
	uint16_t wFormatTag;
	uint16_t nbChannels;
	uint32_t nSamplesPerSec;
	uint32_t nAvgBytesPerSec;
	uint16_t nBlockAlign;
	uint16_t wBitsPerSample;
	uint16_t cbSize;
434 435
} WavPrivate;

François Grisez's avatar
François Grisez committed
436
static void wav_private_set(WavPrivate *data, const MSFmtDescriptor *obj) {
437 438 439
	uint16_t bitsPerSample = 8;
	uint16_t nbBlockAlign = (bitsPerSample * obj->nchannels)/8;
	uint32_t bitrate = bitsPerSample * obj->nchannels * obj->rate;
440

441 442 443 444 445 446 447
	data->wFormatTag = le_uint16((uint16_t)7);
	data->nbChannels = le_uint16((uint16_t)obj->nchannels);
	data->nSamplesPerSec = le_uint32((uint32_t)obj->rate);
	data->nAvgBytesPerSec = le_uint32(bitrate);
	data->nBlockAlign = le_uint16((uint16_t)nbBlockAlign);
	data->wBitsPerSample = le_uint16(bitsPerSample);
	data->cbSize = 0;
448 449
}

François Grisez's avatar
François Grisez committed
450
static void wav_private_serialize(const WavPrivate *obj, uint8_t **data, size_t *size) {
François Grisez's avatar
François Grisez committed
451
	*size = sizeof(WavPrivate);
452 453
	*data = (uint8_t *)ms_new0(uint8_t, *size);
	memcpy(*data, obj, *size);
454 455
}

François Grisez's avatar
François Grisez committed
456
static inline void wav_private_load(WavPrivate *obj, const uint8_t *data) {
François Grisez's avatar
François Grisez committed
457
	memcpy(obj, data, sizeof(WavPrivate));
458 459 460
}

/* µLaw module */
François Grisez's avatar
François Grisez committed
461
static void *mu_law_module_new() {
462
	return ms_new0(WavPrivate, 1);
463 464
}

François Grisez's avatar
François Grisez committed
465
static void mu_law_module_free(void *o) {
466
	ms_free(o);
467 468
}

469
static void mu_law_module_set(void *o, const MSFmtDescriptor *fmt) {
François Grisez's avatar
François Grisez committed
470
	WavPrivate *obj = (WavPrivate *)o;
471
	wav_private_set(obj, fmt);
472 473
}

François Grisez's avatar
François Grisez committed
474
static void mu_law_module_get_private_data(const void *o, uint8_t **data, size_t *data_size) {
François Grisez's avatar
François Grisez committed
475 476
	const WavPrivate *obj = (const WavPrivate *)o;
	wav_private_serialize(obj, data, data_size);
477 478
}

479
static void mu_law_module_load_private(void *o, const uint8_t *data, size_t size) {
François Grisez's avatar
François Grisez committed
480 481
	WavPrivate *obj = (WavPrivate *)o;
	wav_private_load(obj, data);
482 483
}

484
/* µLaw module description */
485
#ifdef _MSC_VER
486
static const ModuleDesc mu_law_module_desc = {
487 488
	"pcmu",
	"A_MS/ACM",
François Grisez's avatar
François Grisez committed
489 490
	mu_law_module_new,
	mu_law_module_free,
491 492 493
	mu_law_module_set,
	NULL,
	NULL,
494
	NULL,
495 496 497
	mu_law_module_get_private_data,
	mu_law_module_load_private,
	NULL
498
};
499
#else
500
static const ModuleDesc mu_law_module_desc = {
501 502 503 504 505 506 507 508 509 510 511 512 513
	.rfcName = "pcmu",
	.codecId = "A_MS/ACM",
	.new_module = mu_law_module_new,
	.free_module = mu_law_module_free,
	.set = mu_law_module_set,
	.preprocess = NULL,
	.process = NULL,
	.reverse = NULL,
	.get_private_data = mu_law_module_get_private_data,
	.load_private_data = mu_law_module_load_private,
	.is_key_frame = NULL
};
#endif
514

515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553
/*********************************************************************************************
 * Opus module                                                                               *
 *********************************************************************************************/
// OpusCodecPrivate
typedef struct {
	uint8_t version;
	uint8_t channelCount;
	uint16_t preSkip;
	uint32_t inputSampleRate;
	uint16_t outputGain;
	uint8_t mappingFamily;
} OpusCodecPrivate;

static void opus_codec_private_init(OpusCodecPrivate *obj) {
	memset(obj, 0, sizeof(OpusCodecPrivate));
	obj->version = 1;
	obj->preSkip = le_uint16(3840); // 80ms at 48kHz
	obj->outputGain = le_uint16(0);
}

static void opus_codec_private_set(OpusCodecPrivate *obj, int nChannels, int inputSampleRate) {
	obj->channelCount = nChannels;
	obj->inputSampleRate = le_uint32((uint32_t)inputSampleRate);
}

static void opus_codec_private_serialize(const OpusCodecPrivate *obj, uint8_t **data, size_t *size) {
	const char signature[9] = "OpusHead";
	*size = 19;
	*data = ms_new0(uint8_t, *size);
	memcpy(*data, signature, 8);
	memcpy((*data)+8, obj, 11);
}

static inline void opus_codec_private_load(OpusCodecPrivate *obj, const uint8_t *data, size_t size) {
	memcpy(obj, data+8, 11);
}

// OpusModule
static void *opus_module_new() {
554
	OpusCodecPrivate *obj = ms_new0(OpusCodecPrivate, 1);
555 556 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 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608
	opus_codec_private_init(obj);
	return obj;
}

static void opus_module_free(void *o) {
	OpusCodecPrivate *obj = (OpusCodecPrivate *)o;
	ms_free(obj);
}

static void opus_module_set(void *o, const MSFmtDescriptor *fmt) {
	OpusCodecPrivate *obj = (OpusCodecPrivate *)o;
	opus_codec_private_set(obj, fmt->nchannels, 0);
}

static void opus_module_get_private_data(const void *o, uint8_t **data, size_t *dataSize) {
	const OpusCodecPrivate *obj = (const OpusCodecPrivate *)o;
	opus_codec_private_serialize(obj, data, dataSize);
}

static void opus_module_load_private_data(void *o, const uint8_t *data, size_t size) {
	OpusCodecPrivate *obj = (OpusCodecPrivate *)o;
	opus_codec_private_load(obj, data, size);
}

#ifdef _MSC_VER
static const ModuleDesc opus_module_desc = {
	"opus",
	"A_OPUS",
	opus_module_new,
	opus_module_free,
	opus_module_set,
	NULL,
	NULL,
	NULL,
	opus_module_get_private_data,
	opus_module_load_private_data,
	NULL
};
#else
static const ModuleDesc opus_module_desc = {
	.rfcName = "opus",
	.codecId = "A_OPUS",
	.new_module = opus_module_new,
	.free_module = opus_module_free,
	.set = opus_module_set,
	.preprocess = NULL,
	.process = NULL,
	.reverse = NULL,
	.get_private_data = opus_module_get_private_data,
	.load_private_data = opus_module_load_private_data,
	.is_key_frame = NULL
};
#endif

609
/*********************************************************************************************
François Grisez's avatar
François Grisez committed
610
 * Modules list                                                                              *
611
 *********************************************************************************************/
François Grisez's avatar
François Grisez committed
612
typedef enum {
613
	H264_MOD_ID,
François Grisez's avatar
François Grisez committed
614
	MU_LAW_MOD_ID,
615
	OPUS_MOD_ID,
François Grisez's avatar
François Grisez committed
616
	NONE_ID
617 618
} ModuleId;

François Grisez's avatar
François Grisez committed
619
static const ModuleDesc *moduleDescs[] = {
620 621
	&h264_module_desc,
	&mu_law_module_desc,
622
	&opus_module_desc,
623
	NULL
624 625
};

François Grisez's avatar
François Grisez committed
626
static int find_module_id_from_rfc_name(const char *rfcName) {
627
	int id;
628
	for(id=0; moduleDescs[id] && strcasecmp(moduleDescs[id]->rfcName, rfcName) != 0; id++);
629
	return id;
630 631
}

François Grisez's avatar
François Grisez committed
632
static int find_module_id_from_codec_id(const char *codecId) {
633
	int id;
634
	for(id=0; moduleDescs[id] && strcmp(moduleDescs[id]->codecId, codecId) != 0; id++);
635
	return id;
636 637
}

638 639 640 641 642 643 644 645 646
static const char *codec_id_to_rfc_name(const char *codecId) {
	ModuleId id = find_module_id_from_codec_id(codecId);
	if(id == NONE_ID) {
		return NULL;
	} else {
		return moduleDescs[id]->rfcName;
	}
}

François Grisez's avatar
François Grisez committed
647 648 649
/*********************************************************************************************
 * Module                                                                                    *
 *********************************************************************************************/
650
typedef struct {
François Grisez's avatar
François Grisez committed
651 652 653 654
	ModuleId id;
	void *data;
} Module;

655
static Module *module_new(const char *rfcName) {
656
	ModuleId id = find_module_id_from_rfc_name(rfcName);
657
	if(id == NONE_ID) {
François Grisez's avatar
François Grisez committed
658
		return NULL;
659 660
	} else {
		Module *module = (Module *)ms_new0(Module, 1);
François Grisez's avatar
François Grisez committed
661 662 663 664 665 666
		module->id = id;
		module->data = moduleDescs[module->id]->new_module();
		return module;
	}
}

667
static void module_free(Module *module) {
François Grisez's avatar
François Grisez committed
668 669 670 671
	moduleDescs[module->id]->free_module(module->data);
	ms_free(module);
}

672 673
static void module_set(Module *module, const MSFmtDescriptor *format) {
	if(moduleDescs[module->id]->set != NULL) {
François Grisez's avatar
François Grisez committed
674
		moduleDescs[module->id]->set(module->data, format);
675
	}
François Grisez's avatar
François Grisez committed
676 677
}

678 679
static void module_preprocess(Module *module, MSQueue *input, MSQueue *output) {
	if(moduleDescs[module->id]->preprocess != NULL) {
François Grisez's avatar
François Grisez committed
680
		moduleDescs[module->id]->preprocess(module->data, input, output);
681
	} else {
François Grisez's avatar
François Grisez committed
682
		mblk_t *buffer;
683
		while((buffer = ms_queue_get(input)) != NULL) {
François Grisez's avatar
François Grisez committed
684 685 686 687 688
			ms_queue_put(output, buffer);
		}
	}
}

689
static mblk_t *module_process(Module *module, mblk_t *buffer, ms_bool_t *isKeyFrame, uint8_t **codecPrivateData, size_t *codecPrivateSize) {
François Grisez's avatar
François Grisez committed
690
	mblk_t *frame;
691
	if(moduleDescs[module->id]->process != NULL) {
692
		frame = moduleDescs[module->id]->process(module->data, buffer, isKeyFrame, codecPrivateData, codecPrivateSize);
693
	} else {
François Grisez's avatar
François Grisez committed
694 695
		frame = buffer;
		*isKeyFrame = TRUE;
696
		*codecPrivateData = NULL;
François Grisez's avatar
François Grisez committed
697 698 699 700
	}
	return frame;
}

701
static void module_reverse(Module *module, mblk_t *input, MSQueue *output, ms_bool_t isFirstFrame, const uint8_t *codecPrivateData, size_t codecPrivateSize) {
702 703 704
	if(moduleDescs[module->id]->reverse == NULL) {
		ms_queue_put(output, input);
	} else {
705
		moduleDescs[module->id]->reverse(module->data, input, output, isFirstFrame, codecPrivateData, codecPrivateSize);
706 707 708 709
	}
}

static inline void module_get_private_data(const Module *module, uint8_t **data, size_t *dataSize) {
François Grisez's avatar
François Grisez committed
710 711 712
	moduleDescs[module->id]->get_private_data(module->data, data, dataSize);
}

713 714
static inline void module_load_private_data(Module *module, const uint8_t *data, size_t size) {
	moduleDescs[module->id]->load_private_data(module->data, data, size);
François Grisez's avatar
François Grisez committed
715 716
}

717
static inline ms_bool_t module_is_key_frame(const Module *module, const mblk_t *frame) {
François Grisez's avatar
François Grisez committed
718 719 720
	return moduleDescs[module->id]->is_key_frame(frame);
}

721
static inline const char *module_get_codec_id(const Module *module) {
François Grisez's avatar
François Grisez committed
722 723 724
	return moduleDescs[module->id]->codecId;
}

725 726 727
/*********************************************************************************************
 * Matroska                                                                                  *
 *********************************************************************************************/
728
#define WRITE_DEFAULT_ELEMENT FALSE
729 730

static const timecode_t MKV_TIMECODE_SCALE = 1000000;
731
static const int MKV_DOCTYPE_VERSION = 4;
732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750
static const int MKV_DOCTYPE_READ_VERSION = 2;

extern const nodemeta LangStr_Class[];
extern const nodemeta UrlPart_Class[];
extern const nodemeta BufStream_Class[];
extern const nodemeta MemStream_Class[];
extern const nodemeta Streams_Class[];
extern const nodemeta File_Class[];
extern const nodemeta Stdio_Class[];
extern const nodemeta Matroska_Class[];
extern const nodemeta EBMLElement_Class[];
extern const nodemeta EBMLMaster_Class[];
extern const nodemeta EBMLBinary_Class[];
extern const nodemeta EBMLString_Class[];
extern const nodemeta EBMLInteger_Class[];
extern const nodemeta EBMLCRC_Class[];
extern const nodemeta EBMLDate_Class[];
extern const nodemeta EBMLVoid_Class[];

François Grisez's avatar
François Grisez committed
751
static void loadModules(nodemodule *modules) {
752 753 754 755 756 757 758 759 760 761 762
	NodeRegisterClassEx(modules, Streams_Class);
	NodeRegisterClassEx(modules, File_Class);
	NodeRegisterClassEx(modules, Matroska_Class);
	NodeRegisterClassEx(modules, EBMLElement_Class);
	NodeRegisterClassEx(modules, EBMLMaster_Class);
	NodeRegisterClassEx(modules, EBMLBinary_Class);
	NodeRegisterClassEx(modules, EBMLString_Class);
	NodeRegisterClassEx(modules, EBMLInteger_Class);
	NodeRegisterClassEx(modules, EBMLCRC_Class);
	NodeRegisterClassEx(modules, EBMLDate_Class);
	NodeRegisterClassEx(modules, EBMLVoid_Class);
763 764
}

765 766 767 768 769 770
typedef enum {
	MKV_OPEN_CREATE,
	MKV_OPEN_APPEND,
	MKV_OPEN_RO
} MatroskaOpenMode;

François Grisez's avatar
François Grisez committed
771
typedef struct {
772 773
	parsercontext *p;
	stream *output;
774
	ebml_master *header, *segment, *cluster, *info, *tracks, *metaSeek, *cues, *firstCluster, *currentCluster;
775
	matroska_seekpoint *infoMeta, *tracksMeta, *cuesMeta;
776
	matroska_block *currentBlock;
777 778 779
	timecode_t timecodeScale;
	filepos_t segmentInfoPosition;
	int nbClusters;
780 781
} Matroska;

François Grisez's avatar
François Grisez committed
782
static void matroska_init(Matroska *obj) {
783
	memset(obj, 0, sizeof(Matroska));
Simon Morlat's avatar
Simon Morlat committed
784
	obj->p = (parsercontext *)ms_new0(parsercontext, 1);
785 786 787
	ParserContext_Init(obj->p, NULL, NULL, NULL);
	loadModules((nodemodule*)obj->p);
	MATROSKA_Init((nodecontext*)obj->p);
788 789
	obj->segmentInfoPosition = -1;
	obj->timecodeScale = -1;
790 791
}

François Grisez's avatar
François Grisez committed
792
static void matroska_uninit(Matroska *obj) {
François Grisez's avatar
François Grisez committed
793 794 795
	MATROSKA_Done((nodecontext*)obj->p);
	ParserContext_Done(obj->p);
	ms_free(obj->p);
796 797
}

798 799
static int ebml_reading_profile(ebml_master *head) {
	char docType[9];
800
	int profile;
801 802
	int docTypeReadVersion;
	
803 804
	EBML_StringGet((ebml_string *)EBML_MasterGetChild(head, &EBML_ContextDocType), docType, sizeof(docType));
	docTypeReadVersion = EBML_IntegerValue((ebml_integer *)EBML_MasterGetChild(head, &EBML_ContextDocTypeReadVersion));
805
	
806

807
	if (strcmp(docType, "matroska")==0) {
François Grisez's avatar
François Grisez committed
808
		switch (docTypeReadVersion) {
809 810 811 812 813 814 815 816 817 818 819 820 821 822 823
		case 1:
			profile = PROFILE_MATROSKA_V1;
			break;
		case 2:
			profile = PROFILE_MATROSKA_V2;
			break;
		case 3:
			profile = PROFILE_MATROSKA_V3;
			break;
		case 4:
			profile = PROFILE_MATROSKA_V4;
			break;
		default:
			profile = -1;
		}
François Grisez's avatar
François Grisez committed
824
	} else if(strcmp(docType, "webm")) {
825
		profile = PROFILE_WEBM;
François Grisez's avatar
François Grisez committed
826
	} else {
827 828
		profile = -1;
	}
829
	
830
	return profile;
831 832
}

François Grisez's avatar
François Grisez committed
833
static ms_bool_t matroska_create_file(Matroska *obj, const char path[]) {
834
	obj->header = (ebml_master *)EBML_ElementCreate(obj->p, &EBML_ContextHead, TRUE, NULL);
835 836 837 838 839 840 841 842 843
	obj->segment = (ebml_master *)EBML_ElementCreate(obj->p, &MATROSKA_ContextSegment, TRUE, NULL);
	obj->metaSeek = (ebml_master *)EBML_MasterAddElt(obj->segment, &MATROSKA_ContextSeekHead, FALSE);
	obj->infoMeta = (matroska_seekpoint *)EBML_MasterAddElt(obj->metaSeek, &MATROSKA_ContextSeek, TRUE);
	obj->tracksMeta = (matroska_seekpoint *)EBML_MasterAddElt(obj->metaSeek, &MATROSKA_ContextSeek, TRUE);
	obj->cuesMeta = (matroska_seekpoint *)EBML_MasterAddElt(obj->metaSeek, &MATROSKA_ContextSeek, TRUE);
	obj->info = (ebml_master *)EBML_MasterAddElt(obj->segment, &MATROSKA_ContextInfo, TRUE);
	obj->tracks = (ebml_master *)EBML_MasterAddElt(obj->segment, &MATROSKA_ContextTracks, FALSE);
	obj->cues = (ebml_master *)EBML_MasterAddElt(obj->segment, &MATROSKA_ContextCues, FALSE);
	obj->timecodeScale = MKV_TIMECODE_SCALE;
844

845 846 847
	MATROSKA_LinkMetaSeekElement(obj->infoMeta, (ebml_element *)obj->info);
	MATROSKA_LinkMetaSeekElement(obj->tracksMeta, (ebml_element *)obj->tracks);
	MATROSKA_LinkMetaSeekElement(obj->cuesMeta, (ebml_element *)obj->cues);
848

849
	return TRUE;
850 851
}

François Grisez's avatar
François Grisez committed
852
static ms_bool_t matroska_load_file(Matroska *obj) {
853 854
	int upperLevels = 0;
	ebml_parser_context readContext;
855 856
	ebml_element *elt;
	
857 858 859 860 861
	readContext.Context = &MATROSKA_ContextStream;
	readContext.EndPosition = INVALID_FILEPOS_T;
	readContext.Profile = 0;
	readContext.UpContext = NULL;

862
	obj->header = (ebml_master *)EBML_FindNextElement(obj->output, &readContext, &upperLevels, FALSE);
863 864 865 866 867 868
	EBML_ElementReadData(obj->header, obj->output, &readContext, FALSE, SCOPE_ALL_DATA, 0);
	readContext.Profile = ebml_reading_profile((ebml_master *)obj->header);

	obj->segment = (ebml_master *)EBML_FindNextElement(obj->output, &readContext, &upperLevels, FALSE);
	EBML_ElementReadData(obj->segment, obj->output, &readContext, FALSE, SCOPE_PARTIAL_DATA, 0);

François Grisez's avatar
François Grisez committed
869 870
	for(elt = EBML_MasterChildren(obj->segment); elt != NULL; elt = EBML_MasterNext(elt)) {
		if(EBML_ElementIsType(elt, &MATROSKA_ContextSeekHead)) {
871
			matroska_seekpoint *seekPoint = NULL;
872 873
			obj->metaSeek = (ebml_master*)elt;
			
François Grisez's avatar
François Grisez committed
874 875
			for(seekPoint = (matroska_seekpoint *)EBML_MasterChildren(obj->metaSeek); seekPoint != NULL; seekPoint = (matroska_seekpoint *)EBML_MasterNext(seekPoint)) {
				if(MATROSKA_MetaSeekIsClass(seekPoint, &MATROSKA_ContextInfo)) {
876
					obj->infoMeta = seekPoint;
François Grisez's avatar
François Grisez committed
877
				} else if(MATROSKA_MetaSeekIsClass(seekPoint, &MATROSKA_ContextTracks)) {
878
					obj->tracksMeta = seekPoint;
François Grisez's avatar
François Grisez committed
879
				} else if(MATROSKA_MetaSeekIsClass(seekPoint, &MATROSKA_ContextCues)) {
880 881 882
					obj->cuesMeta = seekPoint;
				}
			}
François Grisez's avatar
François Grisez committed
883
		} else if(EBML_ElementIsType(elt, &MATROSKA_ContextInfo)) {
884
			obj->info = (ebml_master*)elt;