[haiku-commits] haiku: hrev47470 - in src/tests/kits/media: mpeg2_decoder_test mp3_decoder_test

  • From: coling@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Sun, 6 Jul 2014 14:05:44 +0200 (CEST)

hrev47470 adds 2 changesets to branch 'master'
old head: d71c5a1ebf03722cf032669c54a7b33f0498a4d1
new head: 7a28891db4b5f41f104b83a87c165bb19b02dcfb
overview: http://cgit.haiku-os.org/haiku/log/?qt=range&q=7a28891+%5Ed71c5a1

----------------------------------------------------------------------------

c595436: Media Kit: Add MPEG2 video stream decoder test.
  
  - This test currently fails and thus showing that there is something wrong in
    the Media Kit.
  - This test was first developed and tested on Haiku R1 Alpha 4.1 where
    every thing was hacked together to make this test succeed, thus showing that
    the current Media Kit state of affair has some issues and not this test :)
  - The test comes with documentation (@see mpeg2_decoder.test.cpp).
  
  Signed-off-by: Colin Günther <coling@xxxxxx>

7a28891: Media Kit: Add MP3 audio stream decoder test.
  
  - This test currently fails and thus showing that there is something wrong in
    the Media Kit.
  - This test was first developed and tested on Haiku R1 Alpha 4.1 where
    every thing was hacked together to make this test succeed, thus showing that
    the current Media Kit state of affair has some issues and not this test :)
  - The test comes with documentation (@see mp3_decoder_test.cpp).
  
  Signed-off-by: Colin Günther <coling@xxxxxx>

                                           [ Colin Günther <coling@xxxxxx> ]

----------------------------------------------------------------------------

7 files changed, 634 insertions(+)
src/tests/kits/media/Jamfile                     |   2 +
.../AVCodecTestMp3AudioStreamRaw                 | Bin 0 -> 103680 bytes
src/tests/kits/media/mp3_decoder_test/Jamfile    |  17 +
.../media/mp3_decoder_test/mp3_decoder_test.cpp  | 279 ++++++++++++++++
.../AVCodecTestMpeg2VideoStreamRaw               | Bin 0 -> 1134925 bytes
src/tests/kits/media/mpeg2_decoder_test/Jamfile  |  17 +
.../mpeg2_decoder_test/mpeg2_decoder_test.cpp    | 319 +++++++++++++++++++

############################################################################

Commit:      c5954368ed1b7ff450cf645b395e744694b42ec7
URL:         http://cgit.haiku-os.org/haiku/commit/?id=c595436
Author:      Colin Günther <coling@xxxxxx>
Date:        Sat Jul  5 05:51:57 2014 UTC

Media Kit: Add MPEG2 video stream decoder test.

- This test currently fails and thus showing that there is something wrong in
  the Media Kit.
- This test was first developed and tested on Haiku R1 Alpha 4.1 where
  every thing was hacked together to make this test succeed, thus showing that
  the current Media Kit state of affair has some issues and not this test :)
- The test comes with documentation (@see mpeg2_decoder.test.cpp).

Signed-off-by: Colin Günther <coling@xxxxxx>

----------------------------------------------------------------------------

diff --git a/src/tests/kits/media/Jamfile b/src/tests/kits/media/Jamfile
index 3fe7c21..7292300 100644
--- a/src/tests/kits/media/Jamfile
+++ b/src/tests/kits/media/Jamfile
@@ -18,6 +18,7 @@ SimpleTest mediaDescriptions :
        : media ;
 
 SubInclude HAIKU_TOP src tests kits media media_decoder ;
+SubInclude HAIKU_TOP src tests kits media mpeg2_decoder_test ;
 SubInclude HAIKU_TOP src tests kits media notificationtest ;
 SubInclude HAIKU_TOP src tests kits media nodetest ;
 SubInclude HAIKU_TOP src tests kits media playwav ;
diff --git 
a/src/tests/kits/media/mpeg2_decoder_test/AVCodecTestMpeg2VideoStreamRaw 
b/src/tests/kits/media/mpeg2_decoder_test/AVCodecTestMpeg2VideoStreamRaw
new file mode 100644
index 0000000..feef047
Binary files /dev/null and 
b/src/tests/kits/media/mpeg2_decoder_test/AVCodecTestMpeg2VideoStreamRaw differ
diff --git a/src/tests/kits/media/mpeg2_decoder_test/Jamfile 
b/src/tests/kits/media/mpeg2_decoder_test/Jamfile
new file mode 100644
index 0000000..57b47be
--- /dev/null
+++ b/src/tests/kits/media/mpeg2_decoder_test/Jamfile
@@ -0,0 +1,17 @@
+SubDir HAIKU_TOP src tests kits media mpeg2_decoder_test ;
+
+local ffmpegHeaders = [ BuildFeatureAttribute ffmpeg : headers : path ] ;
+UseHeaders $(ffmpegHeaders) ;
+UseHeaders [ FDirName $(ffmpegHeaders) libavcodec ] ;
+UseHeaders [ FDirName $(ffmpegHeaders) libavformat ] ;
+UseHeaders [ FDirName $(ffmpegHeaders) libavutil ] ;
+
+SubDirC++Flags -D__STDC_CONSTANT_MACROS -Wno-deprecated-declarations ;
+
+SimpleTest mpeg2_decoder_test :
+       mpeg2_decoder_test.cpp
+       : be media translation $(TARGET_LIBSUPC++)
+;
+
+Includes [ FGristFiles mpeg2_decoder_test.cpp ]
+       : [ BuildFeatureAttribute ffmpeg : headers ] ;
diff --git a/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp 
b/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp
new file mode 100644
index 0000000..c943abb
--- /dev/null
+++ b/src/tests/kits/media/mpeg2_decoder_test/mpeg2_decoder_test.cpp
@@ -0,0 +1,319 @@
+/*
+ * Copyright 2014 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Colin Günther, coling@xxxxxx
+ */
+
+
+/*! Tests video stream decoding functionality of the FFMPEG decoder plugin.
+
+       This test is designed with testing the dvb media-addon video decoding
+       capability in mind. Thus we are restricting this test to MPEG2-Video.
+
+       The test requires a MPEG2 test file at the same directory you start the
+       test from. Normally there is a test file included at the same location
+       this source file is located if not have a look at the git history.
+
+       Successful completion of this test results in a series of PNG image
+       files created at the same location you start the test from.
+
+       The originally included test file results in 84 PNG images,
+       representing a movie sequence with the actress Anne Hathaway.
+       This test file has the following properties:
+               - The first frames cannot be decoded, due to missing I-Frames
+                 This is by intention, and helps identifying possible bugs in 
the
+                 FFMPEG decoder plugin regarding decoding of video streams, 
where
+                 the stream may start in the middle of a group of pictures 
(GoP).
+               - encoded_video.output.first_active = 0
+               - encoded_video.output.last_active = 575
+               - encoded_video.output.orientation = B_VIDEO_TOP_LEFT_RIGHT
+               - encoded_video.output.display.format = B_YUV420
+               - encoded_video.output.display.line_width = 720
+               - encoded_video.output.display.line_count = 576
+
+       In any way, there -MUST- be no need to properly initialize those video
+       properties for this test to succeed. To put it in other terms: The
+       FFMPEG decoder plugin should determine those properties by its own and
+       decode the video accordingly.
+*/
+
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <AppKit.h>
+#include <InterfaceKit.h>
+#include <MediaKit.h>
+#include <SupportKit.h>
+#include <TranslationKit.h>
+
+#include <media/Buffer.h>
+#include <media/BufferGroup.h>
+#include <media/MediaDecoder.h>
+#include <storage/File.h>
+#include <support/Errors.h>
+
+
+extern "C" {
+       #include "avcodec.h"
+
+#ifdef DEBUG
+       // Needed to fix debug build, otherwise the linker complains about
+       // "undefined reference to `ff_log2_tab'"
+       const uint8_t ff_log2_tab[256] = {0};
+#endif
+
+}      // extern "C"
+
+
+const char* kTestVideoFilename = "./AVCodecTestMpeg2VideoStreamRaw";
+
+
+class FileDecoder : public BMediaDecoder {
+private:
+       BFile* sourceFile;
+
+public:
+       FileDecoder(BFile* file) : BMediaDecoder() {
+               sourceFile = file;
+       }
+
+protected:
+       virtual status_t        GetNextChunk(const void **chunkData, size_t* 
chunkLen,
+                                                       media_header* mh) {
+               static const uint kReadSizeInBytes = 4096;
+
+               memset(mh, 0, sizeof(media_header));
+
+               void* fileData = malloc(kReadSizeInBytes);
+               ssize_t readLength = this->sourceFile->Read(fileData,
+                       kReadSizeInBytes);
+               if (readLength < 0)
+                       return B_ERROR;
+
+               if (readLength == 0)
+                       return B_LAST_BUFFER_ERROR;
+
+               *chunkData = fileData;
+               *chunkLen = readLength;
+
+               return B_OK;
+       }
+};
+
+
+media_format* CreateMpeg2MediaFormat();
+media_format CreateRawMediaFormat();
+void WriteBufferToImageFileAndRecycleIt(BBuffer* buffer);
+BBitmap* CreateBitmapUsingMediaFormat(media_format mediaFormat);
+status_t SaveBitmapAtPathUsingFormat(BBitmap* bitmap, BString* filePath,
+       uint32 bitmapStorageFormat);
+
+
+int
+main(int argc, char* argv[])
+{
+       BApplication app("application/x-vnd.mpeg2-decoder-test");
+
+       BFile* mpeg2EncodedFile = new BFile(kTestVideoFilename, O_RDONLY);
+       BMediaDecoder* mpeg2Decoder = new FileDecoder(mpeg2EncodedFile);
+
+       media_format* mpeg2MediaFormat = CreateMpeg2MediaFormat();
+       mpeg2Decoder->SetTo(mpeg2MediaFormat);
+       status_t settingMpeg2DecoderStatus = mpeg2Decoder->InitCheck();
+       if (settingMpeg2DecoderStatus < B_OK)
+               exit(1);
+
+       media_format rawMediaFormat = CreateRawMediaFormat();
+       status_t settingMpeg2DecoderOutputStatus
+               = mpeg2Decoder->SetOutputFormat(&rawMediaFormat);
+       if (settingMpeg2DecoderOutputStatus < B_OK)
+               exit(2);
+
+       static const uint32 kVideoBufferRequestTimeout = 20000;
+       uint32 videoBufferSizeInBytesMax = 720 * 576 * 4;
+       BBufferGroup* rawVideoFramesGroup
+               = new BBufferGroup(videoBufferSizeInBytesMax, 4);
+       BBuffer* rawVideoFrame = NULL;
+
+       int64 rawVideoFrameCount = 0;
+       media_header mh;
+       while (true) {
+               rawVideoFrame = rawVideoFramesGroup->RequestBuffer(
+                       videoBufferSizeInBytesMax, kVideoBufferRequestTimeout);
+               status_t decodingVideoFrameStatus = mpeg2Decoder->Decode(
+                       rawVideoFrame->Data(), &rawVideoFrameCount, &mh, NULL);
+               if (decodingVideoFrameStatus < B_OK) {
+                       rawVideoFrame->Recycle();
+                       break;
+               }
+
+               WriteBufferToImageFileAndRecycleIt(rawVideoFrame);
+       }
+
+       // Cleaning up
+       rawVideoFramesGroup->ReclaimAllBuffers();
+}
+
+
+/*!    The caller takes ownership of the returned media_format value.
+       Thus the caller needs to free the returned value.
+       The returned value may be NULL, when there was an error.
+*/
+media_format*
+CreateMpeg2MediaFormat()
+{
+       // The following code is mainly copy 'n' paste from src/add-ons/media/
+       // media-add-ons/dvb/MediaFormat.cpp:GetHeaderFormatMpegVideo()
+
+       status_t status;
+       media_format_description desc;
+       desc.family = B_MISC_FORMAT_FAMILY;
+       desc.u.misc.file_format = 'ffmp';
+       desc.u.misc.codec = CODEC_ID_MPEG2VIDEO;
+       static media_format* kFailedToCreateMpeg2MediaFormat = NULL;
+
+       BMediaFormats formats;
+       status = formats.InitCheck();
+       if (status < B_OK) {
+               printf("formats.InitCheck failed, error %lu\n", status);
+               return kFailedToCreateMpeg2MediaFormat;
+       }
+
+       media_format* mpeg2MediaFormat
+               = static_cast<media_format*>(malloc(sizeof(media_format)));
+       memset(mpeg2MediaFormat, 0, sizeof(media_format));
+       status = formats.GetFormatFor(desc, mpeg2MediaFormat);
+       if (status) {
+               printf("formats.GetFormatFor failed, error %lu\n", status);
+               free(mpeg2MediaFormat);
+               return kFailedToCreateMpeg2MediaFormat;
+       }
+
+       // The following code block can be removed, once the ffmpeg addon can
+       // determine the codec output parameters from the encoded data.
+       mpeg2MediaFormat->u.encoded_video.output.first_active = 0;
+       mpeg2MediaFormat->u.encoded_video.output.last_active = 575;
+       mpeg2MediaFormat->u.encoded_video.output.orientation
+               = B_VIDEO_TOP_LEFT_RIGHT;
+       mpeg2MediaFormat->u.encoded_video.output.display.format = B_YUV420;
+       mpeg2MediaFormat->u.encoded_video.output.display.line_width = 720;
+       mpeg2MediaFormat->u.encoded_video.output.display.line_count = 576;
+
+       return mpeg2MediaFormat;
+}
+
+
+media_format
+CreateRawMediaFormat()
+{
+       media_format rawMediaFormat;
+       memset(&rawMediaFormat, 0, sizeof(media_format));
+
+       rawMediaFormat.type = B_MEDIA_RAW_VIDEO;
+       rawMediaFormat.u.raw_video.display.format = B_RGB32;
+       rawMediaFormat.u.raw_video.display.line_width = 720;
+       rawMediaFormat.u.raw_video.display.line_count = 576;
+       rawMediaFormat.u.raw_video.last_active
+               = rawMediaFormat.u.raw_video.display.line_count - 1;
+       rawMediaFormat.u.raw_video.display.bytes_per_row
+               = rawMediaFormat.u.raw_video.display.line_width * 4;
+       rawMediaFormat.u.raw_video.field_rate = 0; // wildcard
+       rawMediaFormat.u.raw_video.interlace = 1;
+       rawMediaFormat.u.raw_video.first_active = 0;
+       rawMediaFormat.u.raw_video.orientation = B_VIDEO_TOP_LEFT_RIGHT;
+       rawMediaFormat.u.raw_video.pixel_width_aspect = 1;
+       rawMediaFormat.u.raw_video.pixel_height_aspect = 1;
+       rawMediaFormat.u.raw_video.display.pixel_offset = 0;
+       rawMediaFormat.u.raw_video.display.line_offset = 0;
+       rawMediaFormat.u.raw_video.display.flags = 0;
+
+       return rawMediaFormat;
+}
+
+
+void
+WriteBufferToImageFileAndRecycleIt(BBuffer* buffer)
+{
+       static BBitmap* image = NULL;
+
+       if (image == NULL) {
+               // Lazy initialization
+               image = CreateBitmapUsingMediaFormat(CreateRawMediaFormat());
+       }
+
+       if (image == NULL) {
+               // Failed to create the image, needed for converting the buffer
+               buffer->Recycle();
+               return;
+       }
+
+       memcpy(image->Bits(), buffer->Data(), image->BitsLength());
+       buffer->Recycle();
+
+       static int32 imageSavedCounter = 0;
+       static const char* kImageFileNameTemplate = "./mpeg2TestImage%d.png";
+       BString imageFileName;
+       imageFileName.SetToFormat(kImageFileNameTemplate, imageSavedCounter);
+
+       status_t savingBitmapStatus = SaveBitmapAtPathUsingFormat(image,
+               &imageFileName, B_PNG_FORMAT);
+       if (savingBitmapStatus >= B_OK)
+               imageSavedCounter++;
+}
+
+
+BBitmap*
+CreateBitmapUsingMediaFormat(media_format mediaFormat)
+{
+       const uint32 kNoFlags = 0;
+       BBitmap* creatingBitmapFailed = NULL;
+
+       float imageWidth = mediaFormat.u.raw_video.display.line_width;
+       float imageHeight = mediaFormat.u.raw_video.display.line_count;
+       BRect imageFrame(0, 0, imageWidth - 1, imageHeight - 1);
+       color_space imageColorSpace = mediaFormat.u.raw_video.display.format;
+
+       BBitmap* bitmap = NULL;
+
+       bitmap = new BBitmap(imageFrame, kNoFlags, imageColorSpace);
+       if (bitmap == NULL)
+               return bitmap;
+
+       if (bitmap->InitCheck() < B_OK) {
+               delete bitmap;
+               return creatingBitmapFailed;
+       }
+
+       if (bitmap->IsValid() == false) {
+               delete bitmap;
+               return creatingBitmapFailed;
+       }
+
+       return bitmap;
+}
+
+
+status_t
+SaveBitmapAtPathUsingFormat(BBitmap* bitmap, BString* filePath,
+       uint32 bitmapStorageFormat)
+{
+       BFile file(*filePath, B_CREATE_FILE | B_ERASE_FILE | B_WRITE_ONLY);
+       status_t creatingFileStatus = file.InitCheck();
+       if (creatingFileStatus < B_OK)
+               return creatingFileStatus;
+
+       BBitmapStream bitmapStream(bitmap);
+       static BTranslatorRoster* translatorRoster = NULL;
+       if (translatorRoster == NULL)
+               translatorRoster = BTranslatorRoster::Default();
+
+       status_t writingBitmapToFileStatus = translatorRoster->Translate(
+               &bitmapStream, NULL, NULL, &file, bitmapStorageFormat,
+               B_TRANSLATOR_BITMAP);
+       bitmapStream.DetachBitmap(&bitmap);
+
+       return writingBitmapToFileStatus;
+}

############################################################################

Revision:    hrev47470
Commit:      7a28891db4b5f41f104b83a87c165bb19b02dcfb
URL:         http://cgit.haiku-os.org/haiku/commit/?id=7a28891
Author:      Colin Günther <coling@xxxxxx>
Date:        Sat Jul  5 05:51:57 2014 UTC

Media Kit: Add MP3 audio stream decoder test.

- This test currently fails and thus showing that there is something wrong in
  the Media Kit.
- This test was first developed and tested on Haiku R1 Alpha 4.1 where
  every thing was hacked together to make this test succeed, thus showing that
  the current Media Kit state of affair has some issues and not this test :)
- The test comes with documentation (@see mp3_decoder_test.cpp).

Signed-off-by: Colin Günther <coling@xxxxxx>

----------------------------------------------------------------------------

diff --git a/src/tests/kits/media/Jamfile b/src/tests/kits/media/Jamfile
index 7292300..41c4ae2 100644
--- a/src/tests/kits/media/Jamfile
+++ b/src/tests/kits/media/Jamfile
@@ -19,6 +19,7 @@ SimpleTest mediaDescriptions :
 
 SubInclude HAIKU_TOP src tests kits media media_decoder ;
 SubInclude HAIKU_TOP src tests kits media mpeg2_decoder_test ;
+SubInclude HAIKU_TOP src tests kits media mp3_decoder_test ;
 SubInclude HAIKU_TOP src tests kits media notificationtest ;
 SubInclude HAIKU_TOP src tests kits media nodetest ;
 SubInclude HAIKU_TOP src tests kits media playwav ;
diff --git a/src/tests/kits/media/mp3_decoder_test/AVCodecTestMp3AudioStreamRaw 
b/src/tests/kits/media/mp3_decoder_test/AVCodecTestMp3AudioStreamRaw
new file mode 100644
index 0000000..3dce1ed
Binary files /dev/null and 
b/src/tests/kits/media/mp3_decoder_test/AVCodecTestMp3AudioStreamRaw differ
diff --git a/src/tests/kits/media/mp3_decoder_test/Jamfile 
b/src/tests/kits/media/mp3_decoder_test/Jamfile
new file mode 100644
index 0000000..14b701c
--- /dev/null
+++ b/src/tests/kits/media/mp3_decoder_test/Jamfile
@@ -0,0 +1,17 @@
+SubDir HAIKU_TOP src tests kits media mp3_decoder_test ;
+
+local ffmpegHeaders = [ BuildFeatureAttribute ffmpeg : headers : path ] ;
+UseHeaders $(ffmpegHeaders) ;
+UseHeaders [ FDirName $(ffmpegHeaders) libavcodec ] ;
+UseHeaders [ FDirName $(ffmpegHeaders) libavformat ] ;
+UseHeaders [ FDirName $(ffmpegHeaders) libavutil ] ;
+
+SubDirC++Flags -D__STDC_CONSTANT_MACROS -Wno-deprecated-declarations ;
+
+SimpleTest mp3_decoder_test :
+       mp3_decoder_test.cpp
+       : be media $(TARGET_LIBSUPC++)
+;
+
+Includes [ FGristFiles mp3_decoder_test.cpp ]
+       : [ BuildFeatureAttribute ffmpeg : headers ] ;
diff --git a/src/tests/kits/media/mp3_decoder_test/mp3_decoder_test.cpp 
b/src/tests/kits/media/mp3_decoder_test/mp3_decoder_test.cpp
new file mode 100644
index 0000000..b3c9c9d
--- /dev/null
+++ b/src/tests/kits/media/mp3_decoder_test/mp3_decoder_test.cpp
@@ -0,0 +1,279 @@
+/*
+ * Copyright 2014 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *             Colin Günther, coling@xxxxxx
+ */
+
+
+/*!    Tests audio stream decoding functionality of the FFMPEG decoder plugin.
+
+       This test is designed with testing the dvb media-addon audio decoding
+       capability in mind. Thus we are restricting this test to MP3-Audio.
+
+       The test requires a MP3 test file at the same directory you start the
+       test from. Normally there is a test file included at the same location
+       this source file is located if not have a look at the git history.
+
+       Successful completion of this test results in audio being played on the
+       standard system audio output. So turn on your speakers or put on your 
head
+       phones.
+
+       The originally included test file results in an audio signal containing
+       jingles.
+       This test file has the following properties:
+               - encoded_audio.output.frame_rate = 48000
+               - encoded_audio.output.channel_count = 2
+               - encoded_audio.output.buffer_size = 1024
+               - encoded_audio.output.format = 
media_raw_audio_format::B_AUDIO_SHORT
+
+       In any way, there -MUST- be no need to properly initialize those audio
+       properties for this test to succeed. To put it in other terms: The
+       FFMPEG decoder plugin should determine those properties by its own and
+       decode the audio accordingly.
+
+*/
+
+
+#include <pthread.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <AppKit.h>
+#include <InterfaceKit.h>
+#include <MediaKit.h>
+#include <SupportKit.h>
+
+#include <media/Buffer.h>
+#include <media/BufferGroup.h>
+#include <media/MediaDecoder.h>
+#include <media/Sound.h>
+#include <media/SoundPlayer.h>
+#include <storage/File.h>
+#include <support/Errors.h>
+
+
+extern "C" {
+       #include "avcodec.h"
+
+#ifdef DEBUG
+  // Needed to fix debug build, otherwise the linker complains about
+  // "undefined reference to `ff_log2_tab'"
+  const uint8_t ff_log2_tab[256] = {0};
+#endif
+
+}  // extern "C"
+
+
+const char*    kTestAudioFilename = "./AVCodecTestMp3AudioStreamRaw";
+       
+
+class FileDecoder : public BMediaDecoder {
+private:
+       BFile* sourceFile;
+
+public:
+       FileDecoder(BFile* file) : BMediaDecoder() {
+               sourceFile = file;
+       }
+
+protected:
+       virtual status_t        GetNextChunk(const void** chunkData, size_t* 
chunkLen,
+                                                       media_header* mh) {
+               static const uint kReadSizeInBytes = 4096;
+
+               memset(mh, 0, sizeof(media_header));
+
+               void* fileData = malloc(kReadSizeInBytes);
+               ssize_t readLength = this->sourceFile->Read(fileData,
+                       kReadSizeInBytes);
+               if (readLength < 0)
+                       return B_ERROR;
+
+               if (readLength == 0)
+                       return B_LAST_BUFFER_ERROR;
+
+               *chunkData = fileData;
+               *chunkLen = readLength;
+
+               return B_OK;
+       }
+};
+
+
+typedef struct cookie_decode {
+       BFile* inputFile;
+       BMediaDecoder* decoder;
+       BBufferGroup* decodedDataGroup;
+       uint32 decodedDataBufferSizeMax;
+       pthread_cond_t playingFinishedCondition;
+} cookie_decode;
+
+
+status_t InitializeMp3DecodingCookie(cookie_decode* cookie);
+void FreeMp3DecodingCookie(cookie_decode* cookie);
+media_format* CreateMp3MediaFormat();
+media_format CreateRawMediaFormat();
+void Mp3Decoding(void* cookie, void* buffer, size_t bufferSize,
+       const media_raw_audio_format& format);
+
+
+int
+main(int argc, char* argv[])
+{
+       BApplication app("application/x-vnd.mp3-decoder-test");
+
+       cookie_decode decodingCookie;
+       if (InitializeMp3DecodingCookie(&decodingCookie) != B_OK)
+               exit(1);
+
+       media_raw_audio_format* audioOutputFormat
+               = &CreateRawMediaFormat().u.raw_audio;
+
+       BSoundPlayer player(audioOutputFormat, "wave_player", Mp3Decoding,
+               NULL, &decodingCookie);
+       player.Start();
+       player.SetHasData(true);
+       player.SetVolume(0.5);
+
+       // Wait as long as we are playing sound
+       pthread_mutex_t playingFinishedMutex;
+       pthread_mutex_init(&playingFinishedMutex, NULL);
+       pthread_mutex_lock(&playingFinishedMutex);
+       pthread_cond_wait(&decodingCookie.playingFinishedCondition,
+               &playingFinishedMutex);
+
+       player.SetHasData(false);
+       player.Stop();
+
+       // Cleaning up
+       FreeMp3DecodingCookie(&decodingCookie);
+       pthread_mutex_destroy(&playingFinishedMutex);
+}
+
+
+status_t
+InitializeMp3DecodingCookie(cookie_decode* cookie)
+{
+       cookie->inputFile = new BFile(kTestAudioFilename, O_RDONLY);
+       cookie->decoder = new FileDecoder(cookie->inputFile); 
+
+       media_format* mp3MediaFormat = CreateMp3MediaFormat();
+       cookie->decoder->SetTo(mp3MediaFormat);
+       status_t settingDecoderStatus = cookie->decoder->InitCheck();
+       if (settingDecoderStatus < B_OK)
+               return B_ERROR;
+
+       media_format rawMediaFormat = CreateRawMediaFormat();
+       status_t settingDecoderOutputStatus
+               = cookie->decoder->SetOutputFormat(&rawMediaFormat);
+       if (settingDecoderOutputStatus < B_OK)
+               return B_ERROR;
+
+       cookie->decodedDataBufferSizeMax
+               = rawMediaFormat.u.raw_audio.buffer_size * 3;
+       cookie->decodedDataGroup
+               = new BBufferGroup(cookie->decodedDataBufferSizeMax, 25);
+
+       if (pthread_cond_init(&cookie->playingFinishedCondition, NULL) < 0)
+               return B_ERROR;
+
+       return B_OK;
+}
+
+
+void
+FreeMp3DecodingCookie(cookie_decode* cookie)
+{
+       pthread_cond_destroy(&cookie->playingFinishedCondition);
+       cookie->decodedDataGroup->ReclaimAllBuffers();
+       free(cookie->decodedDataGroup);
+       free(cookie->decoder);
+       free(cookie->inputFile);
+}
+
+
+/*!    The caller takes ownership of the returned media_format value.
+       Thus the caller needs to free the returned value.
+       The returned value may be NULL, when there was an error.
+*/
+media_format*
+CreateMp3MediaFormat()
+{
+       // copy 'n' paste from 
src/add-ons/media/media-add-ons/dvb/MediaFormat.cpp:
+       // GetHeaderFormatMpegAudio()
+       status_t status;
+       media_format_description desc;
+       desc.family = B_MISC_FORMAT_FAMILY;
+       desc.u.misc.file_format = 'ffmp';
+       desc.u.misc.codec = CODEC_ID_MP3;
+       static media_format* sNoMp3MediaFormat = NULL;
+
+       BMediaFormats formats;
+       status = formats.InitCheck();
+       if (status < B_OK) {
+               printf("formats.InitCheck failed, error %lu\n", status);
+               return sNoMp3MediaFormat;
+       }
+
+       media_format* mp3MediaFormat
+               = static_cast<media_format*>(malloc(sizeof(media_format)));
+       memset(mp3MediaFormat, 0, sizeof(media_format));
+       status = formats.GetFormatFor(desc, mp3MediaFormat);
+       if (status < B_OK) {
+               printf("formats.GetFormatFor failed, error %lu\n", status);
+               return sNoMp3MediaFormat;
+       }
+
+       // The following code block can be removed, once the ffmpeg addon can
+       // determine the codec output parameters from the encoded data.
+       mp3MediaFormat->u.encoded_audio.output.frame_rate = 48000;
+       mp3MediaFormat->u.encoded_audio.output.channel_count = 2;
+       mp3MediaFormat->u.encoded_audio.output.buffer_size = 1024;
+       mp3MediaFormat->u.encoded_audio.output.format
+               = media_raw_audio_format::B_AUDIO_SHORT;
+
+       return mp3MediaFormat;
+}
+
+
+media_format
+CreateRawMediaFormat()
+{
+       media_format rawMediaFormat;
+       memset(&rawMediaFormat, 0, sizeof(media_format));
+
+       rawMediaFormat.type = B_MEDIA_RAW_AUDIO;
+       rawMediaFormat.u.raw_audio.frame_rate = 48000;
+       rawMediaFormat.u.raw_audio.channel_count = 2;
+       rawMediaFormat.u.raw_audio.format = 
media_raw_audio_format::B_AUDIO_SHORT;
+       rawMediaFormat.u.raw_audio.byte_order = B_MEDIA_HOST_ENDIAN;
+       rawMediaFormat.u.raw_audio.buffer_size = 32768;
+               // comment from src/add-ons/media/media-add-ons/dvb/
+               // DVBMediaNode.cpp::InitDefaultFormats(): when set to anything
+               // different from 32768 haiku mixer has problems
+
+       return rawMediaFormat;
+}
+
+
+void
+Mp3Decoding(void* cookie, void* buffer, size_t bufferSize,
+       const media_raw_audio_format& format)
+{
+       cookie_decode* decodingCookie = static_cast<cookie_decode*>(cookie);
+       int64 rawAudioFrameCount = 0;
+       media_header mh;
+       status_t decodingAudioFramesStatus
+               = decodingCookie->decoder->Decode(buffer, &rawAudioFrameCount, 
&mh,
+                       NULL);
+       if (decodingAudioFramesStatus < B_OK) {
+               sleep(2);
+                       // Give the player some time to catch up playing all 
decoded data.
+                       // The player may still have some data to play, even 
though we run
+                       // out of new data, so don't just tell that we finished 
playing
+                       // quiet yet.
+               pthread_cond_signal(&decodingCookie->playingFinishedCondition);
+       }
+}


Other related posts:

  • » [haiku-commits] haiku: hrev47470 - in src/tests/kits/media: mpeg2_decoder_test mp3_decoder_test - coling