1/*
2 * Copyright 2002-2007, Marcus Overhagen <marcus@overhagen.de>
3 * Copyright 2009-2010, Stephan A��mus <superstippi@gmx.de>
4 * Copyright 2013, Haiku, Inc. All Rights Reserved.
5 * All rights reserved. Distributed under the terms of the MIT license.
6 *
7 * Authors:
8 *		Stephan A��mus, superstippi@gmx.de
9 *		Marcus Overhagen, marcus@overhagen.de
10 */
11
12
13#include <MediaTrack.h>
14
15#include <new>
16
17#include <stdio.h>
18#include <stdlib.h>
19#include <string.h>
20
21#include <Roster.h>
22
23#include "MediaExtractor.h"
24#include "MediaWriter.h"
25#include "PluginManager.h"
26
27
28//#define TRACE_MEDIA_TRACK
29#ifdef TRACE_MEDIA_TRACK
30#	ifndef TRACE
31#		define TRACE printf
32#	endif
33#else
34#	ifndef TRACE
35#		define TRACE(a...)
36#	endif
37#endif
38
39#define ERROR(a...) fprintf(stderr, a)
40
41
42#define CONVERT_TO_INT32 0
43	// TODO: Test! This triggers a few bugs!
44
45// flags used for workarounds
46enum {
47	FORCE_RAW_AUDIO 				= 0x0001,
48	FORCE_RAW_VIDEO 				= 0x0002,
49	FORCE_RAW_AUDIO_INT16_FORMAT 	= 0x0010,
50	FORCE_RAW_AUDIO_INT32_FORMAT 	= 0x0020,
51	FORCE_RAW_AUDIO_FLOAT_FORMAT 	= 0x0040,
52	FORCE_RAW_AUDIO_HOST_ENDIAN 	= 0x0100,
53	IGNORE_ENCODED_AUDIO 			= 0x1000,
54	IGNORE_ENCODED_VIDEO 			= 0x2000,
55};
56
57#define B_MEDIA_DISABLE_FORMAT_TRANSLATION 0x4000
58	// TODO: move this (after name change?) to MediaDefs.h
59
60
61class RawDecoderChunkProvider : public ChunkProvider {
62public:
63							RawDecoderChunkProvider(Decoder* decoder,
64								int buffer_size, int frame_size);
65	virtual					~RawDecoderChunkProvider();
66
67			status_t		GetNextChunk(const void** chunkBuffer,
68								size_t* chunkSize,
69								media_header* mediaHeader);
70
71private:
72			Decoder*		fDecoder;
73			void*			fBuffer;
74			int				fBufferSize;
75			int				fFrameSize;
76};
77
78
79/*************************************************************
80 * protected BMediaTrack
81 *************************************************************/
82
83BMediaTrack::~BMediaTrack()
84{
85	CALLED();
86
87	gPluginManager.DestroyDecoder(fRawDecoder);
88	gPluginManager.DestroyDecoder(fDecoder);
89	gPluginManager.DestroyEncoder(fEncoder);
90}
91
92/*************************************************************
93 * public BMediaTrack
94 *************************************************************/
95
96status_t
97BMediaTrack::InitCheck() const
98{
99	CALLED();
100
101	return fInitStatus;
102}
103
104
105status_t
106BMediaTrack::GetCodecInfo(media_codec_info* _codecInfo) const
107{
108	CALLED();
109
110	if (fDecoder == NULL)
111		return B_NO_INIT;
112
113	*_codecInfo = fCodecInfo;
114	strlcpy(_codecInfo->pretty_name, fCodecInfo.pretty_name,
115		sizeof(_codecInfo->pretty_name));
116
117	return B_OK;
118}
119
120
121status_t
122BMediaTrack::EncodedFormat(media_format* _format) const
123{
124	CALLED();
125
126	if (_format == NULL)
127		return B_BAD_VALUE;
128
129	if (fExtractor == NULL)
130		return B_NO_INIT;
131
132	*_format = *fExtractor->EncodedFormat(fStream);
133
134#ifdef TRACE_MEDIA_TRACK
135	char s[200];
136	string_for_format(*_format, s, sizeof(s));
137	printf("BMediaTrack::EncodedFormat: %s\n", s);
138#endif
139
140	return B_OK;
141}
142
143
144// for BeOS R5 compatibility
145extern "C" status_t DecodedFormat__11BMediaTrackP12media_format(
146	BMediaTrack* self, media_format* _format);
147
148status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack* self,
149	media_format* _format)
150{
151	return self->DecodedFormat(_format, 0);
152}
153
154
155status_t
156BMediaTrack::DecodedFormat(media_format* _format, uint32 flags)
157{
158	CALLED();
159
160	if (_format == NULL)
161		return B_BAD_VALUE;
162
163	if (fExtractor == NULL || fDecoder == NULL)
164		return B_NO_INIT;
165
166	gPluginManager.DestroyDecoder(fRawDecoder);
167	fRawDecoder = NULL;
168
169#ifdef TRACE_MEDIA_TRACK
170	char s[200];
171	string_for_format(*_format, s, sizeof(s));
172	printf("BMediaTrack::DecodedFormat: req1: %s\n", s);
173#endif
174
175	if ((fWorkaroundFlags & FORCE_RAW_AUDIO)
176		|| ((fWorkaroundFlags & IGNORE_ENCODED_AUDIO)
177			&& _format->type == B_MEDIA_ENCODED_AUDIO)) {
178		_format->type = B_MEDIA_RAW_AUDIO;
179		_format->u.raw_audio = media_multi_audio_format::wildcard;
180	}
181	if ((fWorkaroundFlags & FORCE_RAW_VIDEO)
182		|| ((fWorkaroundFlags & IGNORE_ENCODED_VIDEO)
183			&& _format->type == B_MEDIA_ENCODED_VIDEO)) {
184		_format->type = B_MEDIA_RAW_VIDEO;
185		_format->u.raw_video = media_raw_video_format::wildcard;
186	}
187	if (_format->type == B_MEDIA_RAW_AUDIO) {
188		if (fWorkaroundFlags & FORCE_RAW_AUDIO_HOST_ENDIAN)
189			_format->u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
190
191		if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT) {
192			_format->u.raw_audio.format
193				= media_raw_audio_format::B_AUDIO_SHORT;
194		}
195		if (fWorkaroundFlags & FORCE_RAW_AUDIO_INT32_FORMAT) {
196			_format->u.raw_audio.format
197				= media_raw_audio_format::B_AUDIO_INT;
198		}
199		if (fWorkaroundFlags & FORCE_RAW_AUDIO_FLOAT_FORMAT) {
200			_format->u.raw_audio.format
201				= media_raw_audio_format::B_AUDIO_FLOAT;
202		}
203	}
204
205#ifdef TRACE_MEDIA_TRACK
206	string_for_format(*_format, s, sizeof(s));
207	printf("BMediaTrack::DecodedFormat: req2: %s\n", s);
208#endif
209
210	fFormat = *_format;
211	status_t result = fDecoder->NegotiateOutputFormat(_format);
212
213#ifdef TRACE_MEDIA_TRACK
214	string_for_format(*_format, s, sizeof(s));
215	printf("BMediaTrack::DecodedFormat: nego: %s\n", s);
216#endif
217
218	if (_format->type == 0) {
219#ifdef TRACE_MEDIA_TRACK
220		printf("BMediaTrack::DecodedFormat: Decoder didn't set output format "
221			"type.\n");
222#endif
223	}
224
225	if (_format->type == B_MEDIA_RAW_AUDIO) {
226		if (_format->u.raw_audio.byte_order == 0) {
227#ifdef TRACE_MEDIA_TRACK
228			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw audio "
229				"output byte order.\n");
230#endif
231		}
232		if (_format->u.raw_audio.format == 0) {
233#ifdef TRACE_MEDIA_TRACK
234			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw audio "
235				"output sample format.\n");
236#endif
237		}
238		if (_format->u.raw_audio.buffer_size <= 0) {
239#ifdef TRACE_MEDIA_TRACK
240			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw audio "
241				"output buffer size.\n");
242#endif
243		}
244	}
245
246	if (_format->type == B_MEDIA_RAW_VIDEO) {
247		if (_format->u.raw_video.display.format == 0) {
248#ifdef TRACE_MEDIA_TRACK
249			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
250				"output color space.\n");
251#endif
252		}
253		if (_format->u.raw_video.display.line_width == 0) {
254#ifdef TRACE_MEDIA_TRACK
255			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
256				"output line_width.\n");
257#endif
258		}
259		if (_format->u.raw_video.display.line_count == 0) {
260#ifdef TRACE_MEDIA_TRACK
261			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
262				"output line_count.\n");
263#endif
264		}
265		if (_format->u.raw_video.display.bytes_per_row == 0) {
266#ifdef TRACE_MEDIA_TRACK
267			printf("BMediaTrack::DecodedFormat: Decoder didn't set raw video "
268				"output bytes_per_row.\n");
269#endif
270		}
271	}
272
273	if ((flags & B_MEDIA_DISABLE_FORMAT_TRANSLATION) == 0) {
274		if (fFormat.type == B_MEDIA_RAW_AUDIO
275			&& _format->type == B_MEDIA_RAW_AUDIO
276			&& fFormat.u.raw_audio.format != 0
277			&& fFormat.u.raw_audio.format != _format->u.raw_audio.format) {
278			if (SetupFormatTranslation(*_format, &fFormat))
279				*_format = fFormat;
280		}
281	}
282
283	fFormat = *_format;
284
285//	string_for_format(*_format, s, sizeof(s));
286//	printf("BMediaTrack::DecodedFormat: status: %s\n", s);
287	return result;
288}
289
290
291status_t
292BMediaTrack::GetMetaData(BMessage* _data) const
293{
294	CALLED();
295
296	if (fExtractor == NULL)
297		return B_NO_INIT;
298
299	if (_data == NULL)
300		return B_BAD_VALUE;
301
302	_data->MakeEmpty();
303
304	return fExtractor->GetStreamMetaData(fStream, _data);
305}
306
307
308int64
309BMediaTrack::CountFrames() const
310{
311	CALLED();
312
313	int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0;
314//	printf("BMediaTrack::CountFrames: %lld\n", frames);
315	return frames;
316}
317
318
319bigtime_t
320BMediaTrack::Duration() const
321{
322	CALLED();
323
324	bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0;
325//	printf("BMediaTrack::Duration: %lld\n", duration);
326	return duration;
327}
328
329
330int64
331BMediaTrack::CurrentFrame() const
332{
333	return fCurrentFrame;
334}
335
336
337bigtime_t
338BMediaTrack::CurrentTime() const
339{
340	return fCurrentTime;
341}
342
343// BMediaTrack::ReadFrames(char*, long long*, media_header*)
344// Compatibility for R5 and below. Required by Corum III and Civ:CTP.
345#if __GNUC__ < 3
346
347extern "C" status_t
348ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack* self,
349	char* _buffer, int64* _frameCount, media_header* header)
350{
351	return self->ReadFrames(_buffer, _frameCount, header, 0);
352}
353
354#endif	// __GNUC__ < 3
355
356status_t
357BMediaTrack::ReadFrames(void* buffer, int64* _frameCount, media_header* header)
358{
359	return ReadFrames(buffer, _frameCount, header, NULL);
360}
361
362
363status_t
364BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
365	media_header* _header, media_decode_info* info)
366{
367//	CALLED();
368
369	if (fDecoder == NULL)
370		return B_NO_INIT;
371
372	if (buffer == NULL || _frameCount == NULL)
373		return B_BAD_VALUE;
374
375	media_header header;
376	if (_header == NULL)
377		_header = &header;
378
379	// Always clear the header first, as the decoder may not set all fields.
380	memset(_header, 0, sizeof(media_header));
381
382	status_t result = fRawDecoder != NULL
383		? fRawDecoder->Decode(buffer, _frameCount, _header, info)
384		: fDecoder->Decode(buffer, _frameCount, _header, info);
385
386	if (result == B_OK) {
387		fCurrentFrame += *_frameCount;
388		bigtime_t framesDuration = (bigtime_t)(*_frameCount * 1000000
389			/ _FrameRate());
390		fCurrentTime = _header->start_time + framesDuration;
391#if 0
392	// This debug output shows drift between calculated fCurrentFrame and
393	// time-based current frame, if there is any.
394	if (fFormat.type == B_MEDIA_RAW_AUDIO) {
395		printf("current frame: %lld / calculated: %lld (%.2f/%.2f)\r",
396			fCurrentFrame,
397			int64(fCurrentTime * _FrameRate() / 1000000.0 + 0.5),
398			fCurrentTime / 1000000.0, (float)fCurrentFrame / _FrameRate());
399		fflush(stdout);
400	}
401#endif
402	} else {
403		ERROR("BMediaTrack::ReadFrames: decoder returned error %#" B_PRIx32
404			" (%s)\n", result, strerror(result));
405		*_frameCount = 0;
406	}
407
408#if 0
409	PRINT(1, "BMediaTrack::ReadFrames: stream %ld, start-time %5Ld.%06Ld, "
410		"%lld frames\n", fStream,  _header->start_time / 1000000,
411		_header->start_time % 1000000, *out_frameCount);
412#endif
413
414	return result;
415}
416
417
418status_t
419BMediaTrack::ReplaceFrames(const void* inBuffer, int64* _frameCount,
420	const media_header* header)
421{
422	UNIMPLEMENTED();
423
424	// TODO: Actually, a file is either open for reading or writing at the
425	// moment. Since the chunk size of encoded media data will change,
426	// implementing this call will only be possible for raw media tracks.
427
428	return B_NOT_SUPPORTED;
429}
430
431
432status_t
433BMediaTrack::SeekToTime(bigtime_t* _time, int32 flags)
434{
435	CALLED();
436
437	if (fDecoder == NULL || fExtractor == NULL)
438		return B_NO_INIT;
439
440	if (_time == NULL)
441		return B_BAD_VALUE;
442
443	// Make sure flags are valid
444	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME;
445
446	#if DEBUG
447	bigtime_t requestedTime = *_time;
448	#endif
449	int64 frame = 0;
450
451	status_t result = fExtractor->Seek(fStream, flags, &frame, _time);
452	if (result != B_OK) {
453		ERROR("BMediaTrack::SeekToTime: extractor seek failed\n");
454		return result;
455	}
456
457	result = fDecoder->SeekedTo(frame, *_time);
458	if (result != B_OK) {
459		ERROR("BMediaTrack::SeekToTime: decoder seek failed\n");
460		return result;
461	}
462
463	if (fRawDecoder != NULL) {
464		result = fRawDecoder->SeekedTo(frame, *_time);
465		if (result != B_OK) {
466			ERROR("BMediaTrack::SeekToTime: raw decoder seek failed\n");
467			return result;
468		}
469	}
470
471	fCurrentFrame = frame;
472	fCurrentTime = *_time;
473
474	PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n",
475		requestedTime / 1000000.0, *_time / 1000000.0);
476
477	return B_OK;
478}
479
480
481status_t
482BMediaTrack::SeekToFrame(int64* _frame, int32 flags)
483{
484	CALLED();
485
486	if (fDecoder == NULL || fExtractor == NULL)
487		return B_NO_INIT;
488
489	if (_frame == NULL)
490		return B_BAD_VALUE;
491
492	// Make sure flags are valid
493	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME;
494
495	#if DEBUG
496	int64 requestedFrame = *_frame;
497	#endif
498	bigtime_t time = 0;
499
500	status_t result = fExtractor->Seek(fStream, flags, _frame, &time);
501	if (result != B_OK) {
502		ERROR("BMediaTrack::SeekToFrame: extractor seek failed\n");
503		return result;
504	}
505
506	result = fDecoder->SeekedTo(*_frame, time);
507	if (result != B_OK) {
508		ERROR("BMediaTrack::SeekToFrame: decoder seek failed\n");
509		return result;
510	}
511
512	if (fRawDecoder != NULL) {
513		result = fRawDecoder->SeekedTo(*_frame, time);
514		if (result != B_OK) {
515			ERROR("BMediaTrack::SeekToFrame: raw decoder seek failed\n");
516			return result;
517		}
518	}
519
520	fCurrentFrame = *_frame;
521	fCurrentTime = time;
522
523	PRINT(1, "BMediaTrack::SeekToTime SeekToFrame, requested %lld, "
524		"result %lld\n", requestedFrame, *_frame);
525
526	return B_OK;
527}
528
529
530status_t
531BMediaTrack::FindKeyFrameForTime(bigtime_t* _time, int32 flags) const
532{
533	CALLED();
534
535	if (fExtractor == NULL)
536		return B_NO_INIT;
537
538	if (_time == NULL)
539		return B_BAD_VALUE;
540
541	// Make sure flags are valid
542	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_TIME;
543
544	int64 frame = 0;
545		// dummy frame, will be ignored because of flags
546	status_t result = fExtractor->FindKeyFrame(fStream, flags, &frame, _time);
547	if (result != B_OK) {
548		ERROR("BMediaTrack::FindKeyFrameForTime: extractor seek failed: %s\n",
549			strerror(result));
550	}
551
552	return result;
553}
554
555
556status_t
557BMediaTrack::FindKeyFrameForFrame(int64* _frame, int32 flags) const
558{
559	CALLED();
560
561	if (fExtractor == NULL)
562		return B_NO_INIT;
563
564	if (_frame == NULL)
565		return B_BAD_VALUE;
566
567	// Make sure flags are valid
568	flags = (flags & B_MEDIA_SEEK_DIRECTION_MASK) | B_MEDIA_SEEK_TO_FRAME;
569
570	bigtime_t time = 0;
571		// dummy time, will be ignored because of flags
572	status_t result = fExtractor->FindKeyFrame(fStream, flags, _frame, &time);
573	if (result != B_OK) {
574		ERROR("BMediaTrack::FindKeyFrameForFrame: extractor seek failed: %s\n",
575			strerror(result));
576	}
577
578	return result;
579}
580
581
582status_t
583BMediaTrack::ReadChunk(char** _buffer, int32* _size, media_header* _header)
584{
585	CALLED();
586
587	if (fExtractor == NULL)
588		return B_NO_INIT;
589
590	if (_buffer == NULL || _size == NULL)
591		return B_BAD_VALUE;
592
593	media_header header;
594	if (_header == NULL)
595		_header = &header;
596
597	// Always clear the header first, as the extractor may not set all fields.
598	memset(_header, 0, sizeof(media_header));
599
600	const void* buffer;
601	size_t size;
602	status_t result = fExtractor->GetNextChunk(fStream, &buffer, &size,
603		_header);
604
605	if (result == B_OK) {
606		*_buffer = const_cast<char*>(static_cast<const char*>(buffer));
607			// TODO: Change the pointer type when we break the API.
608		*_size = size;
609		// TODO: This changes the meaning of fCurrentTime from pointing
610		// to the next chunk start time (i.e. after seeking) to the start time
611		// of the last chunk. Asking the extractor for the current time will
612		// not work so well because of the chunk cache. But providing a
613		// "duration" field in the media_header could be useful.
614		fCurrentTime = _header->start_time;
615		fCurrentFrame = (int64)(fCurrentTime * _FrameRate() / 1000000LL);
616
617	}
618
619	return result;
620}
621
622
623status_t
624BMediaTrack::AddCopyright(const char* copyright)
625{
626	if (fWriter == NULL)
627		return B_NO_INIT;
628
629	return fWriter->SetCopyright(fStream, copyright);
630}
631
632
633status_t
634BMediaTrack::AddTrackInfo(uint32 code, const void* data, size_t size,
635	uint32 flags)
636{
637	if (fWriter == NULL)
638		return B_NO_INIT;
639
640	return fWriter->AddTrackInfo(fStream, code, data, size, flags);
641}
642
643
644status_t
645BMediaTrack::WriteFrames(const void* data, int32 frameCount, int32 flags)
646{
647	media_encode_info encodeInfo;
648	encodeInfo.flags = flags;
649
650	return WriteFrames(data, frameCount, &encodeInfo);
651}
652
653
654status_t
655BMediaTrack::WriteFrames(const void* data, int64 frameCount,
656	media_encode_info* info)
657{
658	if (fEncoder == NULL)
659		return B_NO_INIT;
660
661	return fEncoder->Encode(data, frameCount, info);
662}
663
664
665status_t
666BMediaTrack::WriteChunk(const void* data, size_t size, uint32 flags)
667{
668	media_encode_info encodeInfo;
669	encodeInfo.flags = flags;
670
671	return WriteChunk(data, size, &encodeInfo);
672}
673
674
675status_t
676BMediaTrack::WriteChunk(const void* data, size_t size, media_encode_info* info)
677{
678	if (fWriter == NULL)
679		return B_NO_INIT;
680
681	return fWriter->WriteChunk(fStream, data, size, info);
682}
683
684
685status_t
686BMediaTrack::Flush()
687{
688	if (fWriter == NULL)
689		return B_NO_INIT;
690
691	return fWriter->Flush();
692}
693
694
695// deprecated BeOS R5 API
696BParameterWeb*
697BMediaTrack::Web()
698{
699	BParameterWeb* web;
700	if (GetParameterWeb(&web) == B_OK)
701		return web;
702
703	return NULL;
704}
705
706
707status_t
708BMediaTrack::GetParameterWeb(BParameterWeb** outWeb)
709{
710	if (outWeb == NULL)
711		return B_BAD_VALUE;
712
713	if (fEncoder == NULL)
714		return B_NO_INIT;
715
716	// TODO: This method is new in Haiku. The header mentions it returns a
717	// copy. But how could it even do that? How can one clone a web and make
718	// it point to the same BControllable?
719	*outWeb = fEncoder->ParameterWeb();
720	if (*outWeb != NULL)
721		return B_OK;
722
723	return B_NOT_SUPPORTED;
724}
725
726
727status_t
728BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size)
729{
730	if (value == NULL || size == NULL)
731		return B_BAD_VALUE;
732
733	if (fEncoder == NULL)
734		return B_NO_INIT;
735
736	return fEncoder->GetParameterValue(id, value, size);
737}
738
739
740status_t
741BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size)
742{
743	if (value == NULL || size == 0)
744		return B_BAD_VALUE;
745
746	if (fEncoder == NULL)
747		return B_NO_INIT;
748
749	return fEncoder->SetParameterValue(id, value, size);
750}
751
752
753BView*
754BMediaTrack::GetParameterView()
755{
756	if (fEncoder == NULL)
757		return NULL;
758
759	return fEncoder->ParameterView();
760}
761
762
763status_t
764BMediaTrack::GetQuality(float* quality)
765{
766	if (quality == NULL)
767		return B_BAD_VALUE;
768
769	encode_parameters parameters;
770	status_t result = GetEncodeParameters(&parameters);
771	if (result != B_OK)
772		return result;
773
774	*quality = parameters.quality;
775
776	return B_OK;
777}
778
779
780status_t
781BMediaTrack::SetQuality(float quality)
782{
783	encode_parameters parameters;
784	status_t result = GetEncodeParameters(&parameters);
785	if (result != B_OK)
786		return result;
787
788	if (quality < 0.0f)
789		quality = 0.0f;
790
791	if (quality > 1.0f)
792		quality = 1.0f;
793
794	parameters.quality = quality;
795
796	return SetEncodeParameters(&parameters);
797}
798
799
800status_t
801BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const
802{
803	if (parameters == NULL)
804		return B_BAD_VALUE;
805
806	if (fEncoder == NULL)
807		return B_NO_INIT;
808
809	return fEncoder->GetEncodeParameters(parameters);
810}
811
812
813status_t
814BMediaTrack::SetEncodeParameters(encode_parameters* parameters)
815{
816	if (parameters == NULL)
817		return B_BAD_VALUE;
818
819	if (fEncoder == NULL)
820		return B_NO_INIT;
821
822	return fEncoder->SetEncodeParameters(parameters);
823}
824
825
826status_t
827BMediaTrack::Perform(int32 selector, void* data)
828{
829	return B_OK;
830}
831
832// #pragma mark - private
833
834
835BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor,
836	int32 stream)
837{
838	CALLED();
839
840	fWorkaroundFlags = 0;
841	fDecoder = NULL;
842	fRawDecoder = NULL;
843	fExtractor = extractor;
844	fStream = stream;
845	fInitStatus = B_OK;
846
847	SetupWorkaround();
848
849	status_t ret = fExtractor->CreateDecoder(fStream, &fDecoder, &fCodecInfo);
850	if (ret != B_OK) {
851		TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
852			"%s\n", strerror(ret));
853		// We do not set fInitStatus here, because ReadChunk should still work.
854		fDecoder = NULL;
855	}
856
857	fCurrentFrame = 0;
858	fCurrentTime = 0;
859
860	// not used:
861	fEncoder = NULL;
862	fEncoderID = 0;
863	fWriter = NULL;
864}
865
866
867BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
868	int32 streamIndex, media_format* format,
869	const media_codec_info* codecInfo)
870{
871	CALLED();
872
873	fWorkaroundFlags = 0;
874	fEncoder = NULL;
875	fEncoderID = -1;
876		// TODO: Not yet sure what this was needed for...
877	fWriter = writer;
878	fStream = streamIndex;
879	fInitStatus = B_OK;
880
881	SetupWorkaround();
882
883	if (codecInfo != NULL) {
884		status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format);
885		if (ret != B_OK) {
886			TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
887				"%s\n", strerror(ret));
888			// We do not set fInitStatus here, because WriteChunk should still
889			// work.
890			fEncoder = NULL;
891		} else {
892			fCodecInfo = *codecInfo;
893			fInitStatus = fEncoder->SetUp(format);
894		}
895	}
896
897	fFormat = *format;
898
899	// not used:
900	fCurrentFrame = 0;
901	fCurrentTime = 0;
902	fDecoder = NULL;
903	fRawDecoder = NULL;
904	fExtractor = NULL;
905}
906
907
908// Does nothing, returns B_ERROR, for Zeta compatiblity only
909status_t
910BMediaTrack::ControlCodec(int32 selector, void* io_data, size_t size)
911{
912	return B_ERROR;
913}
914
915
916void
917BMediaTrack::SetupWorkaround()
918{
919	app_info	ainfo;
920	thread_info	tinfo;
921
922	get_thread_info(find_thread(0), &tinfo);
923	be_roster->GetRunningAppInfo(tinfo.team, &ainfo);
924
925	if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) {
926		fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT
927			| FORCE_RAW_AUDIO_HOST_ENDIAN;
928		printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n");
929	}
930	if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) {
931		fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO;
932		printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n");
933	}
934
935#if CONVERT_TO_INT32
936	// TODO: Test
937	if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT))
938		fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT;
939#endif
940}
941
942
943bool
944BMediaTrack::SetupFormatTranslation(const media_format &from, media_format* to)
945{
946	gPluginManager.DestroyDecoder(fRawDecoder);
947	fRawDecoder = NULL;
948
949#ifdef TRACE_MEDIA_TRACK
950	char s[200];
951	string_for_format(from, s, sizeof(s));
952	printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s);
953#endif
954
955	status_t result = gPluginManager.CreateDecoder(&fRawDecoder, from);
956	if (result != B_OK) {
957		ERROR("BMediaTrack::SetupFormatTranslation: CreateDecoder failed\n");
958		return false;
959	}
960
961	// XXX video?
962	int buffer_size = from.u.raw_audio.buffer_size;
963	int frame_size = (from.u.raw_audio.format & 15)
964		* from.u.raw_audio.channel_count;
965	media_format fromNotConst = from;
966
967	ChunkProvider* chunkProvider
968		= new (std::nothrow) RawDecoderChunkProvider(fDecoder, buffer_size,
969			frame_size);
970	if (chunkProvider == NULL) {
971		ERROR("BMediaTrack::SetupFormatTranslation: can't create chunk "
972			"provider\n");
973		goto error;
974	}
975	fRawDecoder->SetChunkProvider(chunkProvider);
976
977	result = fRawDecoder->Setup(&fromNotConst, 0, 0);
978	if (result != B_OK) {
979		ERROR("BMediaTrack::SetupFormatTranslation: Setup failed\n");
980		goto error;
981	}
982
983#ifdef TRACE_MEDIA_TRACK
984	string_for_format(*to, s, sizeof(s));
985	printf("BMediaTrack::SetupFormatTranslation:   to: %s\n", s);
986#endif
987
988	result = fRawDecoder->NegotiateOutputFormat(to);
989	if (result != B_OK) {
990		ERROR("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat "
991			"failed\n");
992		goto error;
993	}
994
995#ifdef TRACE_MEDIA_TRACK
996	string_for_format(*to, s, sizeof(s));
997	printf("BMediaTrack::SetupFormatTranslation:  result: %s\n", s);
998#endif
999
1000	return true;
1001
1002error:
1003	gPluginManager.DestroyDecoder(fRawDecoder);
1004	fRawDecoder = NULL;
1005	return false;
1006}
1007
1008
1009double
1010BMediaTrack::_FrameRate() const
1011{
1012	switch (fFormat.type) {
1013		case B_MEDIA_RAW_VIDEO:
1014			return fFormat.u.raw_video.field_rate;
1015		case B_MEDIA_ENCODED_VIDEO:
1016			return fFormat.u.encoded_video.output.field_rate;
1017		case B_MEDIA_RAW_AUDIO:
1018			return fFormat.u.raw_audio.frame_rate;
1019		case B_MEDIA_ENCODED_AUDIO:
1020			return fFormat.u.encoded_audio.output.frame_rate;
1021		default:
1022			return 1.0;
1023	}
1024}
1025
1026#if 0
1027// unimplemented
1028BMediaTrack::BMediaTrack()
1029BMediaTrack::BMediaTrack(const BMediaTrack &)
1030BMediaTrack &BMediaTrack::operator=(const BMediaTrack &)
1031#endif
1032
1033status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; }
1034status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; }
1035status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; }
1036status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; }
1037status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; }
1038status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; }
1039status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; }
1040status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; }
1041status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; }
1042status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; }
1043status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; }
1044status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; }
1045status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; }
1046status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; }
1047status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; }
1048status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; }
1049status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; }
1050status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; }
1051status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; }
1052status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; }
1053status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; }
1054status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; }
1055status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; }
1056status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; }
1057status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; }
1058status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; }
1059status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; }
1060status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; }
1061status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; }
1062status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; }
1063status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; }
1064status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; }
1065status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; }
1066status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; }
1067status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; }
1068status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; }
1069status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; }
1070status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; }
1071status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; }
1072status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; }
1073status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; }
1074status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; }
1075status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; }
1076status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; }
1077status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; }
1078status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; }
1079status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; }
1080status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; }
1081
1082
1083RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder* decoder,
1084	int buffer_size, int frame_size)
1085{
1086//	printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n",
1087//		buffer_size, frame_size);
1088	fDecoder = decoder;
1089	fFrameSize = frame_size;
1090	fBufferSize = buffer_size;
1091	fBuffer = malloc(buffer_size);
1092}
1093
1094
1095RawDecoderChunkProvider::~RawDecoderChunkProvider()
1096{
1097	free(fBuffer);
1098}
1099
1100
1101status_t
1102RawDecoderChunkProvider::GetNextChunk(const void** chunkBuffer,
1103	size_t* chunkSize, media_header* header)
1104{
1105	int64 frames;
1106	media_decode_info info;
1107	status_t result = fDecoder->Decode(fBuffer, &frames, header, &info);
1108	if (result == B_OK) {
1109		*chunkBuffer = fBuffer;
1110		*chunkSize = frames * fFrameSize;
1111//		printf("RawDecoderChunkProvider::GetNextChunk, %lld frames, "
1112//			"%ld bytes, start-time %lld\n", frames, *chunkSize,
1113//			header->start_time);
1114	} else
1115		ERROR("RawDecoderChunkProvider::GetNextChunk failed\n");
1116
1117	return result;
1118}
1119