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