xref: /haiku/src/kits/media/MediaTrack.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 	gPluginManager.DestroyDecoder(fRawDecoder);
82 	gPluginManager.DestroyDecoder(fDecoder);
83 	gPluginManager.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 	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 
236 status_t
237 BMediaTrack::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 
251 int64
252 BMediaTrack::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 
261 bigtime_t
262 BMediaTrack::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 
271 int64
272 BMediaTrack::CurrentFrame() const
273 {
274 	return fCurrentFrame;
275 }
276 
277 
278 bigtime_t
279 BMediaTrack::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 
288 extern "C" status_t
289 ReadFrames__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 
299 status_t
300 BMediaTrack::ReadFrames(void* buffer, int64* _frameCount,
301 	media_header* mediaHeader)
302 {
303 	return ReadFrames(buffer, _frameCount, mediaHeader, NULL);
304 }
305 
306 
307 status_t
308 BMediaTrack::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 
356 status_t
357 BMediaTrack::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 
370 status_t
371 BMediaTrack::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 
417 status_t
418 BMediaTrack::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 
464 status_t
465 BMediaTrack::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 
488 status_t
489 BMediaTrack::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 
512 status_t
513 BMediaTrack::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 
551 status_t
552 BMediaTrack::AddCopyright(const char* copyright)
553 {
554 	if (fWriter == NULL)
555 		return B_NO_INIT;
556 
557 	return fWriter->SetCopyright(fStream, copyright);
558 }
559 
560 
561 status_t
562 BMediaTrack::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 
572 status_t
573 BMediaTrack::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 
582 status_t
583 BMediaTrack::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 
593 status_t
594 BMediaTrack::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 
603 status_t
604 BMediaTrack::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 
613 status_t
614 BMediaTrack::Flush()
615 {
616 	if (fWriter == NULL)
617 		return B_NO_INIT;
618 
619 	return fWriter->Flush();
620 }
621 
622 
623 // deprecated BeOS R5 API
624 BParameterWeb*
625 BMediaTrack::Web()
626 {
627 	BParameterWeb* web;
628 	if (GetParameterWeb(&web) == B_OK)
629 		return web;
630 	return NULL;
631 }
632 
633 
634 status_t
635 BMediaTrack::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 
654 status_t
655 BMediaTrack::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 
667 status_t
668 BMediaTrack::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 
680 BView*
681 BMediaTrack::GetParameterView()
682 {
683 	if (fEncoder == NULL)
684 		return NULL;
685 
686 	return fEncoder->ParameterView();
687 }
688 
689 
690 status_t
691 BMediaTrack::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 
707 status_t
708 BMediaTrack::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 
726 status_t
727 BMediaTrack::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 
739 status_t
740 BMediaTrack::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 
752 status_t
753 BMediaTrack::Perform(int32 selector, void* data)
754 {
755 	return B_OK;
756 }
757 
758 // #pragma mark - private
759 
760 
761 BMediaTrack::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 
792 BMediaTrack::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
834 status_t
835 BMediaTrack::ControlCodec(int32 selector, void *io_data, size_t size)
836 {
837 	return B_ERROR;
838 }
839 
840 
841 void
842 BMediaTrack::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 
868 bool
869 BMediaTrack::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 
927 error:
928 	gPluginManager.DestroyDecoder(fRawDecoder);
929 	fRawDecoder = NULL;
930 	return false;
931 }
932 
933 
934 double
935 BMediaTrack::_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
953 BMediaTrack::BMediaTrack()
954 BMediaTrack::BMediaTrack(const BMediaTrack &)
955 BMediaTrack &BMediaTrack::operator=(const BMediaTrack &)
956 */
957 
958 status_t BMediaTrack::_Reserved_BMediaTrack_0(int32 arg, ...) { return B_ERROR; }
959 status_t BMediaTrack::_Reserved_BMediaTrack_1(int32 arg, ...) { return B_ERROR; }
960 status_t BMediaTrack::_Reserved_BMediaTrack_2(int32 arg, ...) { return B_ERROR; }
961 status_t BMediaTrack::_Reserved_BMediaTrack_3(int32 arg, ...) { return B_ERROR; }
962 status_t BMediaTrack::_Reserved_BMediaTrack_4(int32 arg, ...) { return B_ERROR; }
963 status_t BMediaTrack::_Reserved_BMediaTrack_5(int32 arg, ...) { return B_ERROR; }
964 status_t BMediaTrack::_Reserved_BMediaTrack_6(int32 arg, ...) { return B_ERROR; }
965 status_t BMediaTrack::_Reserved_BMediaTrack_7(int32 arg, ...) { return B_ERROR; }
966 status_t BMediaTrack::_Reserved_BMediaTrack_8(int32 arg, ...) { return B_ERROR; }
967 status_t BMediaTrack::_Reserved_BMediaTrack_9(int32 arg, ...) { return B_ERROR; }
968 status_t BMediaTrack::_Reserved_BMediaTrack_10(int32 arg, ...) { return B_ERROR; }
969 status_t BMediaTrack::_Reserved_BMediaTrack_11(int32 arg, ...) { return B_ERROR; }
970 status_t BMediaTrack::_Reserved_BMediaTrack_12(int32 arg, ...) { return B_ERROR; }
971 status_t BMediaTrack::_Reserved_BMediaTrack_13(int32 arg, ...) { return B_ERROR; }
972 status_t BMediaTrack::_Reserved_BMediaTrack_14(int32 arg, ...) { return B_ERROR; }
973 status_t BMediaTrack::_Reserved_BMediaTrack_15(int32 arg, ...) { return B_ERROR; }
974 status_t BMediaTrack::_Reserved_BMediaTrack_16(int32 arg, ...) { return B_ERROR; }
975 status_t BMediaTrack::_Reserved_BMediaTrack_17(int32 arg, ...) { return B_ERROR; }
976 status_t BMediaTrack::_Reserved_BMediaTrack_18(int32 arg, ...) { return B_ERROR; }
977 status_t BMediaTrack::_Reserved_BMediaTrack_19(int32 arg, ...) { return B_ERROR; }
978 status_t BMediaTrack::_Reserved_BMediaTrack_20(int32 arg, ...) { return B_ERROR; }
979 status_t BMediaTrack::_Reserved_BMediaTrack_21(int32 arg, ...) { return B_ERROR; }
980 status_t BMediaTrack::_Reserved_BMediaTrack_22(int32 arg, ...) { return B_ERROR; }
981 status_t BMediaTrack::_Reserved_BMediaTrack_23(int32 arg, ...) { return B_ERROR; }
982 status_t BMediaTrack::_Reserved_BMediaTrack_24(int32 arg, ...) { return B_ERROR; }
983 status_t BMediaTrack::_Reserved_BMediaTrack_25(int32 arg, ...) { return B_ERROR; }
984 status_t BMediaTrack::_Reserved_BMediaTrack_26(int32 arg, ...) { return B_ERROR; }
985 status_t BMediaTrack::_Reserved_BMediaTrack_27(int32 arg, ...) { return B_ERROR; }
986 status_t BMediaTrack::_Reserved_BMediaTrack_28(int32 arg, ...) { return B_ERROR; }
987 status_t BMediaTrack::_Reserved_BMediaTrack_29(int32 arg, ...) { return B_ERROR; }
988 status_t BMediaTrack::_Reserved_BMediaTrack_30(int32 arg, ...) { return B_ERROR; }
989 status_t BMediaTrack::_Reserved_BMediaTrack_31(int32 arg, ...) { return B_ERROR; }
990 status_t BMediaTrack::_Reserved_BMediaTrack_32(int32 arg, ...) { return B_ERROR; }
991 status_t BMediaTrack::_Reserved_BMediaTrack_33(int32 arg, ...) { return B_ERROR; }
992 status_t BMediaTrack::_Reserved_BMediaTrack_34(int32 arg, ...) { return B_ERROR; }
993 status_t BMediaTrack::_Reserved_BMediaTrack_35(int32 arg, ...) { return B_ERROR; }
994 status_t BMediaTrack::_Reserved_BMediaTrack_36(int32 arg, ...) { return B_ERROR; }
995 status_t BMediaTrack::_Reserved_BMediaTrack_37(int32 arg, ...) { return B_ERROR; }
996 status_t BMediaTrack::_Reserved_BMediaTrack_38(int32 arg, ...) { return B_ERROR; }
997 status_t BMediaTrack::_Reserved_BMediaTrack_39(int32 arg, ...) { return B_ERROR; }
998 status_t BMediaTrack::_Reserved_BMediaTrack_40(int32 arg, ...) { return B_ERROR; }
999 status_t BMediaTrack::_Reserved_BMediaTrack_41(int32 arg, ...) { return B_ERROR; }
1000 status_t BMediaTrack::_Reserved_BMediaTrack_42(int32 arg, ...) { return B_ERROR; }
1001 status_t BMediaTrack::_Reserved_BMediaTrack_43(int32 arg, ...) { return B_ERROR; }
1002 status_t BMediaTrack::_Reserved_BMediaTrack_44(int32 arg, ...) { return B_ERROR; }
1003 status_t BMediaTrack::_Reserved_BMediaTrack_45(int32 arg, ...) { return B_ERROR; }
1004 status_t BMediaTrack::_Reserved_BMediaTrack_46(int32 arg, ...) { return B_ERROR; }
1005 status_t BMediaTrack::_Reserved_BMediaTrack_47(int32 arg, ...) { return B_ERROR; }
1006 
1007 
1008 RawDecoderChunkProvider::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 
1017 RawDecoderChunkProvider::~RawDecoderChunkProvider()
1018 {
1019 	free(fBuffer);
1020 }
1021 
1022 status_t
1023 RawDecoderChunkProvider::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