[haiku-commits] r39039 - haiku/trunk/src/add-ons/media/plugins/ffmpeg

  • From: superstippi@xxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 21 Oct 2010 12:29:21 +0200 (CEST)

Author: stippi
Date: 2010-10-21 12:29:20 +0200 (Thu, 21 Oct 2010)
New Revision: 39039
Changeset: http://dev.haiku-os.org/changeset/39039

Modified:
   haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp
   haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h
   haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp
Log:
 * Introduce some currently disabled code to store the AVCodecContext
   pointer in the media_format user data section.
 * In the AVCodecEncoder, optionally use the AVCodecContext pointer
   from the AVFormatWriter instead of its own instance. The problems
   I am investigating are not improved by this, but it may be needed
   anyway.
 * Map the bitrate for audio to a fixed table. Certain encoders will
   refuse to use a non-standard bitrate, like the currently enabled
   AC-3 encoder.
 * Fixed tracing output in _EncodeAudio().


Modified: haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp
===================================================================
--- haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp     
2010-10-21 09:00:07 UTC (rev 39038)
+++ haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.cpp     
2010-10-21 10:29:20 UTC (rev 39039)
@@ -11,6 +11,9 @@
 #include <stdio.h>
 #include <string.h>
 
+#include <Application.h>
+#include <Roster.h>
+
 extern "C" {
        #include "rational.h"
 }
@@ -39,7 +42,8 @@
        fBitRateScale(bitRateScale),
        fCodecID((enum CodecID)codecID),
        fCodec(NULL),
-       fContext(avcodec_alloc_context()),
+       fOwnContext(avcodec_alloc_context()),
+       fContext(fOwnContext),
        fCodecInitStatus(CODEC_INIT_NEEDED),
 
        fFrame(avcodec_alloc_frame()),
@@ -105,7 +109,7 @@
                free(fFrame);
        }
 
-       free(fContext);
+       free(fOwnContext);
 
        delete[] fChunkBuffer;
 }
@@ -157,6 +161,23 @@
        fInputFormat = *inputFormat;
        fFramesWritten = 0;
 
+       const uchar* userData = inputFormat->user_data;
+       if (*(uint32*)userData == 'ffmp') {
+               userData += sizeof(uint32);
+               // The Writer plugin used is the FFmpeg plugin. It stores the
+               // AVCodecContext pointer in the user data section. Use this
+               // context instead of our own. It requires the Writer living in
+               // the same team, of course.
+               app_info appInfo;
+               if (be_app->GetAppInfo(&appInfo) == B_OK
+                       && *(team_id*)userData == appInfo.team) {
+                       userData += sizeof(team_id);
+                       // Use the AVCodecContext from the Writer. This works 
better
+                       // than using our own context with some encoders.
+                       fContext = *(AVCodecContext**)userData;
+               }
+       }
+
        return _Setup();
 }
 
@@ -202,7 +223,11 @@
                return B_NOT_SUPPORTED;
 
        fEncodeParameters.quality = parameters->quality;
-       TRACE("  quality: %.1f\n", parameters->quality);
+       TRACE("  quality: %.5f\n", parameters->quality);
+       if (fEncodeParameters.quality == 0.0f) {
+               TRACE("  using default quality (1.0)\n");
+               fEncodeParameters.quality = 1.0f;
+       }
 
 // TODO: Auto-bit_rate versus user supplied. See above.
 //     int avgBytesPerSecond = 0;
@@ -401,14 +426,38 @@
                return B_NOT_SUPPORTED;
        }
 
+       // TODO: Support letting the user overwrite this via
+       // SetEncodeParameters(). See comments there...
        int wantedBitRate = (int)(rawBitRate / fBitRateScale
                * fEncodeParameters.quality);
-       TRACE("  rawBitRate: %d, wantedBitRate: %d (%.1f)\n", rawBitRate,
-               wantedBitRate, fEncodeParameters.quality);
-       // TODO: Support letting the user overwrite this via
-       // SetEncodeParameters(). See comments there...
+       if (wantedBitRate == 0)
+               wantedBitRate = (int)(rawBitRate / fBitRateScale);
+
        fContext->bit_rate = wantedBitRate;
 
+       if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
+               // Some audio encoders support certain bitrates only. Use the
+               // closest match to the wantedBitRate.
+               const int kBitRates[] = {
+                       32000, 40000, 48000, 56000, 64000, 80000, 96000, 
112000, 128000,
+                       160000, 192000, 224000, 256000, 320000, 384000, 448000, 
512000,
+                       576000, 640000
+               };
+               int diff = wantedBitRate;
+               for (int i = 0; i < sizeof(kBitRates) / sizeof(int); i++) {
+                       int currentDiff = abs(wantedBitRate - kBitRates[i]);
+                       if (currentDiff < diff) {
+                               fContext->bit_rate = kBitRates[i];
+                               diff = currentDiff;
+                       } else
+                               break;
+               }
+       }
+
+       TRACE("  rawBitRate: %d, wantedBitRate: %d (%.1f), "
+               "context bitrate: %d\n", rawBitRate, wantedBitRate,
+               fEncodeParameters.quality, fContext->bit_rate);
+
        // Add some known fixes from the FFmpeg API example:
        if (fContext->codec_id == CODEC_ID_MPEG2VIDEO) {
                // Just for testing, we also add B frames */
@@ -430,6 +479,12 @@
 bool
 AVCodecEncoder::_OpenCodecIfNeeded()
 {
+       if (fContext != fOwnContext) {
+               // We are using the AVCodecContext of the AVFormatWriter plugin,
+               // and don't maintain it's open/close state.
+               return true;
+       }
+
        if (fCodecInitStatus == CODEC_INIT_DONE)
                return true;
 
@@ -443,7 +498,7 @@
        else
                fCodecInitStatus = CODEC_INIT_FAILED;
 
-       TRACE("  avcodec_open(): %d\n", result);
+       TRACE("  avcodec_open(%p, %p): %d\n", fContext, fCodec, result);
 
        return fCodecInitStatus == CODEC_INIT_DONE;
 
@@ -453,6 +508,11 @@
 void
 AVCodecEncoder::_CloseCodecIfNeeded()
 {
+       if (fContext != fOwnContext) {
+               // See _OpenCodecIfNeeded().
+               return;
+       }
+
        if (fCodecInitStatus == CODEC_INIT_DONE) {
                avcodec_close(fContext);
                fCodecInitStatus = CODEC_INIT_NEEDED;
@@ -536,7 +596,7 @@
                bufferSize, reinterpret_cast<const short*>(buffer));
 
        if (usedBytes < 0) {
-               TRACE("  avcodec_encode_video() failed: %d\n", usedBytes);
+               TRACE("  avcodec_encode_audio() failed: %d\n", usedBytes);
                return B_ERROR;
        }
        if (usedBytes == 0)

Modified: haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h
===================================================================
--- haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h       
2010-10-21 09:00:07 UTC (rev 39038)
+++ haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVCodecEncoder.h       
2010-10-21 10:29:20 UTC (rev 39039)
@@ -68,6 +68,7 @@
                        // TODO: Refactor common base class from 
AVCodec[De|En]Coder!
                        CodecID                         fCodecID;
                        AVCodec*                        fCodec;
+                       AVCodecContext*         fOwnContext;
                        AVCodecContext*         fContext;
 
                        enum {

Modified: haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp
===================================================================
--- haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp     
2010-10-21 09:00:07 UTC (rev 39038)
+++ haiku/trunk/src/add-ons/media/plugins/ffmpeg/AVFormatWriter.cpp     
2010-10-21 10:29:20 UTC (rev 39039)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Stephan Aßmus <superstippi@xxxxxx>
+ * Copyright 2009-2010, Stephan Aßmus <superstippi@xxxxxx>
  * All rights reserved. Distributed under the terms of the GNU L-GPL license.
  */
 
@@ -11,12 +11,14 @@
 
 #include <new>
 
+#include <Application.h>
 #include <AutoDeleter.h>
 #include <Autolock.h>
 #include <ByteOrder.h>
 #include <DataIO.h>
 #include <MediaDefs.h>
 #include <MediaFormats.h>
+#include <Roster.h>
 
 extern "C" {
        #include "avformat.h"
@@ -234,6 +236,23 @@
                fStream->time_base.num, fStream->time_base.den,
                fStream->codec->time_base.num, fStream->codec->time_base.den);
 
+#if 0
+       // Write the AVCodecContext pointer to the user data section of the
+       // media_format. For some encoders, it seems to be necessary to use
+       // the AVCodecContext of the AVStream in order to successfully encode
+       // anything and write valid media files. For example some codecs need
+       // to store meta data or global data in the container.
+       app_info appInfo;
+       if (be_app->GetAppInfo(&appInfo) == B_OK) {
+               uchar* userData = format->user_data;
+               *(uint32*)userData = 'ffmp';
+               userData += sizeof(uint32);
+               *(team_id*)userData = appInfo.team;
+               userData += sizeof(team_id);
+               *(AVCodecContext**)userData = fStream->codec;
+       }
+#endif
+
        return B_OK;
 }
 


Other related posts:

  • » [haiku-commits] r39039 - haiku/trunk/src/add-ons/media/plugins/ffmpeg - superstippi