* 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(). git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@39039 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
672b4d7800
commit
657983b8c2
@ -11,6 +11,9 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
|
#include <Roster.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "rational.h"
|
#include "rational.h"
|
||||||
}
|
}
|
||||||
@ -39,7 +42,8 @@ AVCodecEncoder::AVCodecEncoder(uint32 codecID, int bitRateScale)
|
|||||||
fBitRateScale(bitRateScale),
|
fBitRateScale(bitRateScale),
|
||||||
fCodecID((enum CodecID)codecID),
|
fCodecID((enum CodecID)codecID),
|
||||||
fCodec(NULL),
|
fCodec(NULL),
|
||||||
fContext(avcodec_alloc_context()),
|
fOwnContext(avcodec_alloc_context()),
|
||||||
|
fContext(fOwnContext),
|
||||||
fCodecInitStatus(CODEC_INIT_NEEDED),
|
fCodecInitStatus(CODEC_INIT_NEEDED),
|
||||||
|
|
||||||
fFrame(avcodec_alloc_frame()),
|
fFrame(avcodec_alloc_frame()),
|
||||||
@ -105,7 +109,7 @@ AVCodecEncoder::~AVCodecEncoder()
|
|||||||
free(fFrame);
|
free(fFrame);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(fContext);
|
free(fOwnContext);
|
||||||
|
|
||||||
delete[] fChunkBuffer;
|
delete[] fChunkBuffer;
|
||||||
}
|
}
|
||||||
@ -157,6 +161,23 @@ AVCodecEncoder::SetUp(const media_format* inputFormat)
|
|||||||
fInputFormat = *inputFormat;
|
fInputFormat = *inputFormat;
|
||||||
fFramesWritten = 0;
|
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();
|
return _Setup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -202,7 +223,11 @@ AVCodecEncoder::SetEncodeParameters(encode_parameters* parameters)
|
|||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
|
|
||||||
fEncodeParameters.quality = parameters->quality;
|
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.
|
// TODO: Auto-bit_rate versus user supplied. See above.
|
||||||
// int avgBytesPerSecond = 0;
|
// int avgBytesPerSecond = 0;
|
||||||
@ -401,14 +426,38 @@ AVCodecEncoder::_Setup()
|
|||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// TODO: Support letting the user overwrite this via
|
||||||
// SetEncodeParameters(). See comments there...
|
// SetEncodeParameters(). See comments there...
|
||||||
|
int wantedBitRate = (int)(rawBitRate / fBitRateScale
|
||||||
|
* fEncodeParameters.quality);
|
||||||
|
if (wantedBitRate == 0)
|
||||||
|
wantedBitRate = (int)(rawBitRate / fBitRateScale);
|
||||||
|
|
||||||
fContext->bit_rate = wantedBitRate;
|
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:
|
// Add some known fixes from the FFmpeg API example:
|
||||||
if (fContext->codec_id == CODEC_ID_MPEG2VIDEO) {
|
if (fContext->codec_id == CODEC_ID_MPEG2VIDEO) {
|
||||||
// Just for testing, we also add B frames */
|
// Just for testing, we also add B frames */
|
||||||
@ -430,6 +479,12 @@ AVCodecEncoder::_Setup()
|
|||||||
bool
|
bool
|
||||||
AVCodecEncoder::_OpenCodecIfNeeded()
|
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)
|
if (fCodecInitStatus == CODEC_INIT_DONE)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -443,7 +498,7 @@ AVCodecEncoder::_OpenCodecIfNeeded()
|
|||||||
else
|
else
|
||||||
fCodecInitStatus = CODEC_INIT_FAILED;
|
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;
|
return fCodecInitStatus == CODEC_INIT_DONE;
|
||||||
|
|
||||||
@ -453,6 +508,11 @@ AVCodecEncoder::_OpenCodecIfNeeded()
|
|||||||
void
|
void
|
||||||
AVCodecEncoder::_CloseCodecIfNeeded()
|
AVCodecEncoder::_CloseCodecIfNeeded()
|
||||||
{
|
{
|
||||||
|
if (fContext != fOwnContext) {
|
||||||
|
// See _OpenCodecIfNeeded().
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (fCodecInitStatus == CODEC_INIT_DONE) {
|
if (fCodecInitStatus == CODEC_INIT_DONE) {
|
||||||
avcodec_close(fContext);
|
avcodec_close(fContext);
|
||||||
fCodecInitStatus = CODEC_INIT_NEEDED;
|
fCodecInitStatus = CODEC_INIT_NEEDED;
|
||||||
@ -536,7 +596,7 @@ AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize,
|
|||||||
bufferSize, reinterpret_cast<const short*>(buffer));
|
bufferSize, reinterpret_cast<const short*>(buffer));
|
||||||
|
|
||||||
if (usedBytes < 0) {
|
if (usedBytes < 0) {
|
||||||
TRACE(" avcodec_encode_video() failed: %d\n", usedBytes);
|
TRACE(" avcodec_encode_audio() failed: %d\n", usedBytes);
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
if (usedBytes == 0)
|
if (usedBytes == 0)
|
||||||
|
@ -68,6 +68,7 @@ private:
|
|||||||
// TODO: Refactor common base class from AVCodec[De|En]Coder!
|
// TODO: Refactor common base class from AVCodec[De|En]Coder!
|
||||||
CodecID fCodecID;
|
CodecID fCodecID;
|
||||||
AVCodec* fCodec;
|
AVCodec* fCodec;
|
||||||
|
AVCodecContext* fOwnContext;
|
||||||
AVCodecContext* fContext;
|
AVCodecContext* fContext;
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2009, Stephan Aßmus <superstippi@gmx.de>
|
* Copyright 2009-2010, Stephan Aßmus <superstippi@gmx.de>
|
||||||
* All rights reserved. Distributed under the terms of the GNU L-GPL license.
|
* All rights reserved. Distributed under the terms of the GNU L-GPL license.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -11,12 +11,14 @@
|
|||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
|
#include <Application.h>
|
||||||
#include <AutoDeleter.h>
|
#include <AutoDeleter.h>
|
||||||
#include <Autolock.h>
|
#include <Autolock.h>
|
||||||
#include <ByteOrder.h>
|
#include <ByteOrder.h>
|
||||||
#include <DataIO.h>
|
#include <DataIO.h>
|
||||||
#include <MediaDefs.h>
|
#include <MediaDefs.h>
|
||||||
#include <MediaFormats.h>
|
#include <MediaFormats.h>
|
||||||
|
#include <Roster.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "avformat.h"
|
#include "avformat.h"
|
||||||
@ -234,6 +236,23 @@ AVFormatWriter::StreamCookie::Init(media_format* format,
|
|||||||
fStream->time_base.num, fStream->time_base.den,
|
fStream->time_base.num, fStream->time_base.den,
|
||||||
fStream->codec->time_base.num, fStream->codec->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;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user