xref: /haiku/src/kits/media/MediaTrack.cpp (revision b55a57da7173b9af0432bd3e148d03f06161d036)
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
42 enum {
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 
57 class RawDecoderChunkProvider : public ChunkProvider {
58 public:
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 
66 private:
67 	Decoder*	fDecoder;
68 	void*		fBuffer;
69 	int			fBufferSize;
70 	int			fFrameSize;
71 };
72 
73 
74 /*************************************************************
75  * protected BMediaTrack
76  *************************************************************/
77 
78 BMediaTrack::~BMediaTrack()
79 {
80 	CALLED();
81 	_plugin_manager.DestroyDecoder(fRawDecoder);
82 	_plugin_manager.DestroyDecoder(fDecoder);
83 	_plugin_manager.DestroyEncoder(fEncoder);
84 }
85 
86 /*************************************************************
87  * public BMediaTrack
88  *************************************************************/
89 
90 status_t
91 BMediaTrack::InitCheck() const
92 {
93 	CALLED();
94 	return fInitStatus;
95 }
96 
97 
98 status_t
99 BMediaTrack::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 
112 status_t
113 BMediaTrack::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
134 extern "C" status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack *self, media_format *inout_format);
135 status_t DecodedFormat__11BMediaTrackP12media_format(BMediaTrack *self,
136 													 media_format *inout_format)
137 {
138 	return self->DecodedFormat(inout_format, 0);
139 }
140 
141 
142 status_t
143 BMediaTrack::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 	_plugin_manager.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 
236 int64
237 BMediaTrack::CountFrames() const
238 {
239 	CALLED();
240 	int64 frames = fExtractor ? fExtractor->CountFrames(fStream) : 0;
241 //	printf("BMediaTrack::CountFrames: %Ld\n", frames);
242 	return frames;
243 }
244 
245 
246 bigtime_t
247 BMediaTrack::Duration() const
248 {
249 	CALLED();
250 	bigtime_t duration = fExtractor ? fExtractor->Duration(fStream) : 0;
251 //	printf("BMediaTrack::Duration: %Ld\n", duration);
252 	return duration;
253 }
254 
255 
256 int64
257 BMediaTrack::CurrentFrame() const
258 {
259 	return fCurrentFrame;
260 }
261 
262 
263 bigtime_t
264 BMediaTrack::CurrentTime() const
265 {
266 	return fCurrentTime;
267 }
268 
269 // BMediaTrack::ReadFrames(char *, long long *, media_header *)
270 // Compatibility for R5 and below. Required by Corum III and Civ:CTP.
271 #if __GNUC__ < 3
272 
273 extern "C" status_t
274 ReadFrames__11BMediaTrackPcPxP12media_header(BMediaTrack *self,
275 											 char *out_buffer,
276 											 int64 *out_frameCount,
277 											 media_header *mh)
278 {
279 	return self->ReadFrames(out_buffer, out_frameCount, mh, 0);
280 }
281 
282 #endif	// __GNUC__ < 3
283 
284 status_t
285 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
286 	media_header* mediaHeader)
287 {
288 	return ReadFrames(buffer, _frameCount, mediaHeader, NULL);
289 }
290 
291 
292 status_t
293 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
294 	media_header* _header, media_decode_info* info)
295 {
296 //	CALLED();
297 	if (!fDecoder)
298 		return B_NO_INIT;
299 	if (!buffer || !_frameCount)
300 		return B_BAD_VALUE;
301 
302 	media_header header;
303 	if (_header == NULL)
304 		_header = &header;
305 
306 	// Always clear the header first, as the decoder may not set all fields.
307 	memset(_header, 0, sizeof(media_header));
308 
309 	status_t result;
310 	if (fRawDecoder)
311 		result = fRawDecoder->Decode(buffer, _frameCount, _header, info);
312 	else
313 		result = fDecoder->Decode(buffer, _frameCount, _header, info);
314 	if (result == B_OK) {
315 		fCurrentFrame += *_frameCount;
316 		// TODO: This changes the meaning of fCurrentTime from pointing
317 		// to the next chunk start time (i.e. after seeking) to the start time
318 		// of the last chunk. Asking the extractor for the current time will
319 		// not work so well because of the chunk cache. But providing a
320 		// "duration" field in the media_header could be useful.
321 		fCurrentTime = fCurrentTime = _header->start_time;
322 	} else {
323 		ERROR("BMediaTrack::ReadFrames: decoder returned error 0x%08lx (%s)\n",
324 			result, strerror(result));
325 		*_frameCount = 0;
326 	}
327 
328 //	PRINT(1, "BMediaTrack::ReadFrames: stream %ld, start-time %5Ld.%06Ld, "
329 //		"%Ld frames\n", fStream,  _header->start_time / 1000000,
330 //		_header->start_time % 1000000, *out_frameCount);
331 
332 	return result;
333 }
334 
335 
336 status_t
337 BMediaTrack::ReplaceFrames(const void* inBuffer, int64* inOutFrameCount,
338 	const media_header* mediaHeader)
339 {
340 	UNIMPLEMENTED();
341 
342 	// TODO: Actually, a file is either open for reading or writing at the
343 	// moment. Since the chunk size of encoded media data will change,
344 	// implementing this call will only be possible for raw media tracks.
345 
346 	return B_NOT_SUPPORTED;
347 }
348 
349 
350 status_t
351 BMediaTrack::SeekToTime(bigtime_t* inOutTime, int32 flags)
352 {
353 	CALLED();
354 	if (!fDecoder || !fExtractor)
355 		return B_NO_INIT;
356 	if (!inOutTime)
357 		return B_BAD_VALUE;
358 
359 	uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK)
360 		| B_MEDIA_SEEK_TO_TIME;
361 	bigtime_t seekTime = *inOutTime;
362 
363 	int64 frame = 0;
364 	bigtime_t time = seekTime;
365 	status_t result = fExtractor->Seek(fStream, seekTo, &frame, &time);
366 	if (result != B_OK) {
367 		ERROR("BMediaTrack::SeekToTime: extractor seek failed\n");
368 		return result;
369 	}
370 
371 	// TODO: Codecs cannot actually "seek" in the stream, all they
372 	// can do is "reset" their decoder state, since they are made
373 	// aware of the fact that there will be a jump in the data. Maybe
374 	// rename the Decoder method?
375 	result = fDecoder->Seek(seekTo, 0, &frame, seekTime, &time);
376 	if (result != B_OK) {
377 		ERROR("BMediaTrack::SeekToTime: decoder seek failed\n");
378 		return result;
379 	}
380 
381 	if (fRawDecoder) {
382 		result = fRawDecoder->Seek(seekTo, 0, &frame, seekTime, &time);
383 		if (result != B_OK) {
384 			ERROR("BMediaTrack::SeekToTime: raw decoder seek failed\n");
385 			return result;
386 		}
387 	}
388 
389 	*inOutTime = time;
390 	fCurrentFrame = frame;
391 	fCurrentTime = time;
392 
393 	PRINT(1, "BMediaTrack::SeekToTime finished, requested %.6f, result %.6f\n",
394 		seekTime / 1000000.0, *inOutTime / 1000000.0);
395 
396 	return B_OK;
397 }
398 
399 
400 status_t
401 BMediaTrack::SeekToFrame(int64 *inout_frame, int32 flags)
402 {
403 	CALLED();
404 	if (!fDecoder || !fExtractor)
405 		return B_NO_INIT;
406 	if (!inout_frame)
407 		return B_BAD_VALUE;
408 
409 	uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK)
410 		| B_MEDIA_SEEK_TO_FRAME;
411 	int64 seekFrame = *inout_frame;
412 
413 	int64 frame = seekFrame;
414 	bigtime_t time = 0;
415 	status_t result = fExtractor->Seek(fStream, seekTo, &frame, &time);
416 	if (result != B_OK) {
417 		ERROR("BMediaTrack::SeekToFrame: extractor seek failed\n");
418 		return result;
419 	}
420 
421 	// TODO: Codecs cannot actually "seek" in the stream, all they
422 	// can do is "reset" their decoder state, since they are made
423 	// aware of the fact that there will be a jump in the data. Maybe
424 	// rename the codec method?
425 	result = fDecoder->Seek(seekTo, seekFrame, &frame, 0, &time);
426 	if (result != B_OK) {
427 		ERROR("BMediaTrack::SeekToFrame: decoder seek failed\n");
428 		return result;
429 	}
430 
431 	if (fRawDecoder) {
432 		result = fRawDecoder->Seek(seekTo, seekFrame, &frame, 0, &time);
433 		if (result != B_OK) {
434 			ERROR("BMediaTrack::SeekToFrame: raw decoder seek failed\n");
435 			return result;
436 		}
437 	}
438 
439 	*inout_frame = frame;
440 	fCurrentFrame = frame;
441 	fCurrentTime = time;
442 
443 	PRINT(1, "BMediaTrack::SeekToTime SeekToFrame, requested %Ld, result %Ld\n", seekFrame, *inout_frame);
444 
445 	return B_OK;
446 }
447 
448 
449 status_t
450 BMediaTrack::FindKeyFrameForTime(bigtime_t *inoutTime, int32 flags) const
451 {
452 	CALLED();
453 	if (!fExtractor)
454 		return B_NO_INIT;
455 	if (!inoutTime)
456 		return B_BAD_VALUE;
457 
458 	uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK)
459 		| B_MEDIA_SEEK_TO_TIME;
460 
461 	int64 frame = 0;
462 		// dummy frame, will be ignored because of flags
463 	status_t result = fExtractor->FindKeyFrame(fStream, seekTo, &frame,
464 		inoutTime);
465 	if (result != B_OK) {
466 		ERROR("BMediaTrack::FindKeyFrameForTime: extractor seek failed: %s\n",
467 			strerror(result));
468 		return result;
469 	}
470 
471 	return B_OK;
472 }
473 
474 
475 status_t
476 BMediaTrack::FindKeyFrameForFrame(int64 *inoutFrame,
477 								  int32 flags) const
478 {
479 	CALLED();
480 	if (!fExtractor)
481 		return B_NO_INIT;
482 	if (!inoutFrame)
483 		return B_BAD_VALUE;
484 
485 	uint32 seekTo = (flags & B_MEDIA_SEEK_DIRECTION_MASK)
486 		| B_MEDIA_SEEK_TO_FRAME;
487 
488 	bigtime_t time = 0;
489 		// dummy time, will be ignored because of flags
490 	status_t result = fExtractor->FindKeyFrame(fStream, seekTo, inoutFrame,
491 		&time);
492 	if (result != B_OK) {
493 		ERROR("BMediaTrack::FindKeyFrameForFrame: extractor seek failed: %s\n",
494 			strerror(result));
495 		return result;
496 	}
497 
498 	return B_OK;
499 }
500 
501 
502 status_t
503 BMediaTrack::ReadChunk(char** _buffer, int32* _size, media_header* _header)
504 {
505 	CALLED();
506 	if (fExtractor == NULL)
507 		return B_NO_INIT;
508 	if (_buffer == NULL || _size == NULL)
509 		return B_BAD_VALUE;
510 
511 	media_header header;
512 	if (_header == NULL)
513 		_header = &header;
514 
515 	// Always clear the header first, as the extractor may not set all fields.
516 	memset(_header, 0, sizeof(media_header));
517 
518 	const void* buffer;
519 	size_t size;
520 	status_t result = fExtractor->GetNextChunk(fStream, &buffer, &size,
521 		_header);
522 
523 	if (result == B_OK) {
524 		*_buffer = const_cast<char*>(static_cast<const char*>(buffer));
525 			// TODO: Change the pointer type when we break the API.
526 		*_size = size;
527 		// TODO: This changes the meaning of fCurrentTime from pointing
528 		// to the next chunk start time (i.e. after seeking) to the start time
529 		// of the last chunk. Asking the extractor for the current time will
530 		// not work so well because of the chunk cache. But providing a
531 		// "duration" field in the media_header could be useful.
532 		fCurrentTime = fCurrentTime = _header->start_time;
533 		fCurrentFrame = fCurrentTime * _FrameRate() / 1000000LL;
534 
535 	}
536 
537 	return result;
538 }
539 
540 
541 status_t
542 BMediaTrack::AddCopyright(const char* copyright)
543 {
544 	if (fWriter == NULL)
545 		return B_NO_INIT;
546 
547 	return fWriter->SetCopyright(fStream, copyright);
548 }
549 
550 
551 status_t
552 BMediaTrack::AddTrackInfo(uint32 code, const void* data, size_t size,
553 	uint32 flags)
554 {
555 	if (fWriter == NULL)
556 		return B_NO_INIT;
557 
558 	return fWriter->AddTrackInfo(fStream, code, data, size, flags);
559 }
560 
561 
562 status_t
563 BMediaTrack::WriteFrames(const void* data, int32 frameCount, int32 flags)
564 {
565 	media_encode_info encodeInfo;
566 	encodeInfo.flags = flags;
567 
568 	return WriteFrames(data, frameCount, &encodeInfo);
569 }
570 
571 
572 status_t
573 BMediaTrack::WriteFrames(const void* data, int64 frameCount,
574 	media_encode_info* info)
575 {
576 	if (fEncoder == NULL)
577 		return B_NO_INIT;
578 
579 	return fEncoder->Encode(data, frameCount, info);
580 }
581 
582 
583 status_t
584 BMediaTrack::WriteChunk(const void* data, size_t size, uint32 flags)
585 {
586 	media_encode_info encodeInfo;
587 	encodeInfo.flags = flags;
588 
589 	return WriteChunk(data, size, &encodeInfo);
590 }
591 
592 
593 status_t
594 BMediaTrack::WriteChunk(const void* data, size_t size, media_encode_info* info)
595 {
596 	if (fWriter == NULL)
597 		return B_NO_INIT;
598 
599 	return fWriter->WriteChunk(fStream, data, size, info);
600 }
601 
602 
603 status_t
604 BMediaTrack::Flush()
605 {
606 	if (fWriter == NULL)
607 		return B_NO_INIT;
608 
609 	return fWriter->Flush();
610 }
611 
612 
613 // deprecated BeOS R5 API
614 BParameterWeb*
615 BMediaTrack::Web()
616 {
617 	BParameterWeb* web;
618 	if (GetParameterWeb(&web) == B_OK)
619 		return web;
620 	return NULL;
621 }
622 
623 
624 status_t
625 BMediaTrack::GetParameterWeb(BParameterWeb** outWeb)
626 {
627 	if (outWeb == NULL)
628 		return B_BAD_VALUE;
629 
630 	if (fEncoder == NULL)
631 		return B_NO_INIT;
632 
633 	// TODO: This method is new in Haiku. The header mentions it returns a
634 	// copy. But how could it even do that? How can one clone a web and make
635 	// it point to the same BControllable?
636 	*outWeb = fEncoder->ParameterWeb();
637 	if (*outWeb != NULL)
638 		return B_OK;
639 
640 	return B_NOT_SUPPORTED;
641 }
642 
643 
644 status_t
645 BMediaTrack::GetParameterValue(int32 id, void* value, size_t* size)
646 {
647 	if (value == NULL || size == NULL)
648 		return B_BAD_VALUE;
649 
650 	if (fEncoder == NULL)
651 		return B_NO_INIT;
652 
653 	return fEncoder->GetParameterValue(id, value, size);
654 }
655 
656 
657 status_t
658 BMediaTrack::SetParameterValue(int32 id, const void* value, size_t size)
659 {
660 	if (value == NULL || size == 0)
661 		return B_BAD_VALUE;
662 
663 	if (fEncoder == NULL)
664 		return B_NO_INIT;
665 
666 	return fEncoder->SetParameterValue(id, value, size);
667 }
668 
669 
670 BView*
671 BMediaTrack::GetParameterView()
672 {
673 	if (fEncoder == NULL)
674 		return NULL;
675 
676 	return fEncoder->ParameterView();
677 }
678 
679 
680 status_t
681 BMediaTrack::GetQuality(float* quality)
682 {
683 	if (quality == NULL)
684 		return B_BAD_VALUE;
685 
686 	encode_parameters parameters;
687 	status_t ret = GetEncodeParameters(&parameters);
688 	if (ret != B_OK)
689 		return ret;
690 
691 	*quality = parameters.quality;
692 
693 	return B_OK;
694 }
695 
696 
697 status_t
698 BMediaTrack::SetQuality(float quality)
699 {
700 	encode_parameters parameters;
701 	status_t ret = GetEncodeParameters(&parameters);
702 	if (ret != B_OK)
703 		return ret;
704 
705 	if (quality < 0.0f)
706 		quality = 0.0f;
707 	if (quality > 1.0f)
708 		quality = 1.0f;
709 
710 	parameters.quality = quality;
711 
712 	return SetEncodeParameters(&parameters);
713 }
714 
715 
716 status_t
717 BMediaTrack::GetEncodeParameters(encode_parameters* parameters) const
718 {
719 	if (parameters == NULL)
720 		return B_BAD_VALUE;
721 
722 	if (fEncoder == NULL)
723 		return B_NO_INIT;
724 
725 	return fEncoder->GetEncodeParameters(parameters);
726 }
727 
728 
729 status_t
730 BMediaTrack::SetEncodeParameters(encode_parameters *parameters)
731 {
732 	if (parameters == NULL)
733 		return B_BAD_VALUE;
734 
735 	if (fEncoder == NULL)
736 		return B_NO_INIT;
737 
738 	return fEncoder->SetEncodeParameters(parameters);
739 }
740 
741 
742 status_t
743 BMediaTrack::Perform(int32 selector, void* data)
744 {
745 	return B_OK;
746 }
747 
748 // #pragma mark - private
749 
750 
751 BMediaTrack::BMediaTrack(BPrivate::media::MediaExtractor* extractor,
752 	int32 stream)
753 {
754 	CALLED();
755 	fWorkaroundFlags = 0;
756 	fDecoder = NULL;
757 	fRawDecoder = NULL;
758 	fExtractor = extractor;
759 	fStream = stream;
760 	fInitStatus = B_OK;
761 
762 	SetupWorkaround();
763 
764 	status_t ret = fExtractor->CreateDecoder(fStream, &fDecoder, &fCodecInfo);
765 	if (ret != B_OK) {
766 		TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
767 			"%s\n", strerror(ret));
768 		// We do not set fInitStatus here, because ReadChunk should still work.
769 		fDecoder = NULL;
770 	}
771 
772 	fCurrentFrame = 0;
773 	fCurrentTime = 0;
774 
775 	// not used:
776 	fEncoder = NULL;
777 	fEncoderID = 0;
778 	fWriter = NULL;
779 }
780 
781 
782 BMediaTrack::BMediaTrack(BPrivate::media::MediaWriter* writer,
783 	int32 streamIndex, const media_format* format,
784 	const media_codec_info* codecInfo)
785 {
786 	CALLED();
787 
788 	fWorkaroundFlags = 0;
789 	fEncoder = NULL;
790 	fEncoderID = -1;
791 		// TODO: Not yet sure what this was needed for...
792 	fWriter = writer;
793 	fFormat = *format;
794 	fStream = streamIndex;
795 	fInitStatus = B_OK;
796 
797 	SetupWorkaround();
798 
799 	if (codecInfo != NULL) {
800 		status_t ret = fWriter->CreateEncoder(&fEncoder, codecInfo, format);
801 		if (ret != B_OK) {
802 			TRACE("BMediaTrack::BMediaTrack: Error: creating decoder failed: "
803 				"%s\n", strerror(ret));
804 			// We do not set fInitStatus here, because WriteChunk should still work.
805 			fEncoder = NULL;
806 		} else {
807 			fCodecInfo = *codecInfo;
808 			fInitStatus = fEncoder->SetUp(&fFormat);
809 		}
810 	}
811 
812 	// not used:
813 	fCurrentFrame = 0;
814 	fCurrentTime = 0;
815 	fDecoder = NULL;
816 	fRawDecoder = NULL;
817 	fExtractor = NULL;
818 }
819 
820 
821 // Does nothing, returns B_ERROR, for Zeta compatiblity only
822 status_t
823 BMediaTrack::ControlCodec(int32 selector, void *io_data, size_t size)
824 {
825 	return B_ERROR;
826 }
827 
828 
829 void
830 BMediaTrack::SetupWorkaround()
831 {
832 	app_info	ainfo;
833 	thread_info	tinfo;
834 
835 	get_thread_info(find_thread(0), &tinfo);
836 	be_roster->GetRunningAppInfo(tinfo.team, &ainfo);
837 
838 	if (strcmp(ainfo.signature, "application/x-vnd.marcone-soundplay") == 0) {
839 		fWorkaroundFlags = FORCE_RAW_AUDIO | FORCE_RAW_AUDIO_INT16_FORMAT
840 			| FORCE_RAW_AUDIO_HOST_ENDIAN;
841 		printf("BMediaTrack::SetupWorkaround: SoundPlay workaround active\n");
842 	}
843 	if (strcmp(ainfo.signature, "application/x-vnd.Be.MediaPlayer") == 0) {
844 		fWorkaroundFlags = IGNORE_ENCODED_AUDIO | IGNORE_ENCODED_VIDEO;
845 		printf("BMediaTrack::SetupWorkaround: MediaPlayer workaround active\n");
846 	}
847 
848 #if CONVERT_TO_INT32
849 	// TODO: Test
850 	if (!(fWorkaroundFlags & FORCE_RAW_AUDIO_INT16_FORMAT))
851 		fWorkaroundFlags |= FORCE_RAW_AUDIO_INT32_FORMAT;
852 #endif
853 }
854 
855 
856 bool
857 BMediaTrack::SetupFormatTranslation(const media_format &from, media_format *to)
858 {
859 	_plugin_manager.DestroyDecoder(fRawDecoder);
860 	fRawDecoder = NULL;
861 
862 #ifdef TRACE_MEDIA_TRACK
863 	char s[200];
864 	string_for_format(from, s, sizeof(s));
865 	printf("BMediaTrack::SetupFormatTranslation: from: %s\n", s);
866 #endif
867 
868 	status_t res = _plugin_manager.CreateDecoder(&fRawDecoder, from);
869 	if (res != B_OK) {
870 		ERROR("BMediaTrack::SetupFormatTranslation: CreateDecoder failed\n");
871 		return false;
872 	}
873 
874 	// XXX video?
875 	int buffer_size = from.u.raw_audio.buffer_size;
876 	int frame_size = (from.u.raw_audio.format & 15)
877 		* from.u.raw_audio.channel_count;
878 	media_format notconstFrom = from;
879 
880 	ChunkProvider *chunkProvider
881 		= new(std::nothrow) RawDecoderChunkProvider(fDecoder, buffer_size,
882 			frame_size);
883 	if (!chunkProvider) {
884 		ERROR("BMediaTrack::SetupFormatTranslation: can't create chunk "
885 			"provider\n");
886 		goto error;
887 	}
888 	fRawDecoder->SetChunkProvider(chunkProvider);
889 
890 	res = fRawDecoder->Setup(&notconstFrom, 0, 0);
891 	if (res != B_OK) {
892 		ERROR("BMediaTrack::SetupFormatTranslation: Setup failed\n");
893 		goto error;
894 	}
895 
896 #ifdef TRACE_MEDIA_TRACK
897 	string_for_format(*to, s, sizeof(s));
898 	printf("BMediaTrack::SetupFormatTranslation:   to: %s\n", s);
899 #endif
900 
901 	res = fRawDecoder->NegotiateOutputFormat(to);
902 	if (res != B_OK) {
903 		ERROR("BMediaTrack::SetupFormatTranslation: NegotiateOutputFormat "
904 			"failed\n");
905 		goto error;
906 	}
907 
908 #ifdef TRACE_MEDIA_TRACK
909 	string_for_format(*to, s, sizeof(s));
910 	printf("BMediaTrack::SetupFormatTranslation:  res: %s\n", s);
911 #endif
912 
913 	return true;
914 
915 error:
916 	_plugin_manager.DestroyDecoder(fRawDecoder);
917 	fRawDecoder = NULL;
918 	return false;
919 }
920 
921 
922 double
923 BMediaTrack::_FrameRate() const
924 {
925 	switch (fFormat.type) {
926 		case B_MEDIA_RAW_VIDEO:
927 			return fFormat.u.raw_video.field_rate;
928 		case B_MEDIA_ENCODED_VIDEO:
929 			return fFormat.u.encoded_video.output.field_rate;
930 		case B_MEDIA_RAW_AUDIO:
931 			return fFormat.u.raw_audio.frame_rate;
932 		case B_MEDIA_ENCODED_AUDIO:
933 			return fFormat.u.encoded_audio.output.frame_rate;
934 		default:
935 			return 1.0;
936 	}
937 }
938 
939 /*
940 // unimplemented
941 BMediaTrack::BMediaTrack()
942 BMediaTrack::BMediaTrack(const BMediaTrack &)
943 BMediaTrack &BMediaTrack::operator=(const BMediaTrack &)
944 */
945 
946 status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; }
947 status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; }
948 status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; }
949 status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; }
950 status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; }
951 status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; }
952 status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; }
953 status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; }
954 status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; }
955 status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; }
956 status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; }
957 status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; }
958 status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; }
959 status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; }
960 status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; }
961 status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; }
962 status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; }
963 status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; }
964 status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; }
965 status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; }
966 status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; }
967 status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; }
968 status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; }
969 status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; }
970 status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; }
971 status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; }
972 status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; }
973 status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; }
974 status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; }
975 status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; }
976 status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; }
977 status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; }
978 status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; }
979 status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; }
980 status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; }
981 status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; }
982 status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; }
983 status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; }
984 status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; }
985 status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; }
986 status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; }
987 status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; }
988 status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; }
989 status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; }
990 status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; }
991 status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; }
992 status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; }
993 status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; }
994 
995 
996 RawDecoderChunkProvider::RawDecoderChunkProvider(Decoder *decoder, int buffer_size, int frame_size)
997 {
998 //	printf("RawDecoderChunkProvider: buffer_size %d, frame_size %d\n", buffer_size, frame_size);
999 	fDecoder = decoder;
1000 	fFrameSize = frame_size;
1001 	fBufferSize = buffer_size;
1002 	fBuffer = malloc(buffer_size);
1003 }
1004 
1005 RawDecoderChunkProvider::~RawDecoderChunkProvider()
1006 {
1007 	free(fBuffer);
1008 }
1009 
1010 status_t
1011 RawDecoderChunkProvider::GetNextChunk(const void **chunkBuffer, size_t *chunkSize,
1012                                       media_header *mediaHeader)
1013 {
1014 	int64 frames;
1015 	media_decode_info info;
1016 	status_t res = fDecoder->Decode(fBuffer, &frames, mediaHeader, &info);
1017 	if (res == B_OK) {
1018 		*chunkBuffer = fBuffer;
1019 		*chunkSize = frames * fFrameSize;
1020 //		printf("RawDecoderChunkProvider::GetNextChunk, %Ld frames, %ld bytes, start-time %Ld\n", frames, *chunkSize, mediaHeader->start_time);
1021 	} else {
1022 		ERROR("RawDecoderChunkProvider::GetNextChunk failed\n");
1023 	}
1024 	return res;
1025 }
1026