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