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