Now supports encoded audio. Added Dolby Digital (AC-3) encoding to test this.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32105 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
6ca5e0f9fa
commit
6e567425c6
|
@ -9,6 +9,7 @@
|
|||
#include <new>
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
extern "C" {
|
||||
#include "rational.h"
|
||||
|
@ -46,9 +47,11 @@ AVCodecEncoder::AVCodecEncoder(uint32 codecID)
|
|||
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
|
||||
|
||||
fCodec = avcodec_find_encoder((enum CodecID)codecID);
|
||||
TRACE(" found AVCodec: %p\n", fCodec);
|
||||
TRACE(" found AVCodec for %lu: %p\n", codecID, fCodec);
|
||||
|
||||
memset(&fInputFormat, 0, sizeof(media_format));
|
||||
|
||||
av_fifo_init(&fAudioFifo, 0);
|
||||
}
|
||||
|
||||
|
||||
|
@ -337,66 +340,84 @@ AVCodecEncoder::_EncodeAudio(const void* _buffer, int64 frameCount,
|
|||
size_t bufferSize = frameCount * inputFrameSize;
|
||||
bufferSize = min_c(bufferSize, kDefaultChunkBufferSize);
|
||||
|
||||
while (frameCount > 0) {
|
||||
if (frameCount < fContext->frame_size) {
|
||||
TRACE(" ERROR: too few frames left! (left: %lld, needed: %d)\n",
|
||||
frameCount, fContext->frame_size);
|
||||
// TODO: Handle this some way. Maybe use an av_fifo to buffer data?
|
||||
return B_ERROR;
|
||||
if (fContext->frame_size > 1) {
|
||||
// Encoded audio. Things work differently from raw audio. We need
|
||||
// the fAudioFifo to pipe data.
|
||||
if (av_fifo_realloc2(&fAudioFifo,
|
||||
av_fifo_size(&fAudioFifo) + bufferSize) < 0) {
|
||||
TRACE(" av_fifo_realloc2() failed\n");
|
||||
return B_NO_MEMORY;
|
||||
}
|
||||
av_fifo_generic_write(&fAudioFifo, const_cast<uint8*>(buffer),
|
||||
bufferSize, NULL);
|
||||
|
||||
int frameBytes = fContext->frame_size * inputFrameSize;
|
||||
uint8* tempBuffer = new(std::nothrow) uint8[frameBytes];
|
||||
if (tempBuffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// Encode as many chunks as can be read from the FIFO.
|
||||
while (av_fifo_size(&fAudioFifo) >= frameBytes) {
|
||||
av_fifo_read(&fAudioFifo, tempBuffer, frameBytes);
|
||||
|
||||
ret = _EncodeAudio(tempBuffer, frameBytes, fContext->frame_size,
|
||||
info);
|
||||
if (ret != B_OK)
|
||||
break;
|
||||
}
|
||||
|
||||
int chunkFrames = fContext->frame_size;
|
||||
|
||||
TRACE(" frames left: %lld, chunk frames: %d\n",
|
||||
frameCount, chunkFrames);
|
||||
|
||||
// Encode one audio chunk/frame.
|
||||
int usedBytes = avcodec_encode_audio(fContext, fChunkBuffer,
|
||||
bufferSize, reinterpret_cast<const short*>(buffer));
|
||||
|
||||
if (usedBytes < 0) {
|
||||
TRACE(" avcodec_encode_video() failed: %d\n", usedBytes);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Maybe we need to use this PTS to calculate start_time:
|
||||
if (fContext->coded_frame->pts != kNoPTSValue) {
|
||||
TRACE(" codec frame PTS: %lld (codec time_base: %d/%d)\n",
|
||||
fContext->coded_frame->pts, fContext->time_base.num,
|
||||
fContext->time_base.den);
|
||||
} else {
|
||||
TRACE(" codec frame PTS: N/A (codec time_base: %d/%d)\n",
|
||||
fContext->time_base.num, fContext->time_base.den);
|
||||
}
|
||||
|
||||
// Setup media_encode_info, most important is the time stamp.
|
||||
info->start_time = (bigtime_t)(fFramesWritten * 1000000LL
|
||||
/ fInputFormat.u.raw_audio.frame_rate);
|
||||
|
||||
// Write the chunk
|
||||
ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
||||
if (ret != B_OK)
|
||||
break;
|
||||
|
||||
size_t framesWritten = usedBytes / inputFrameSize;
|
||||
if (chunkFrames == 1) {
|
||||
// For PCM data:
|
||||
framesWritten = usedBytes / inputFrameSize;
|
||||
} else {
|
||||
// For encoded audio:
|
||||
framesWritten = chunkFrames * inputFrameSize;
|
||||
}
|
||||
|
||||
// Skip to next chunk of buffer.
|
||||
fFramesWritten += framesWritten;
|
||||
frameCount -= framesWritten;
|
||||
buffer += usedBytes;
|
||||
} else {
|
||||
// Raw audio. The number of bytes returned from avcodec_encode_audio()
|
||||
// is always the same as the number of input bytes.
|
||||
return _EncodeAudio(buffer, bufferSize, frameCount,
|
||||
info);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecEncoder::_EncodeAudio(const uint8* buffer, size_t bufferSize,
|
||||
int64 frameCount, media_encode_info* info)
|
||||
{
|
||||
// Encode one audio chunk/frame. The bufferSize has already been adapted
|
||||
// to the needed size for fContext->frame_size, or we are writing raw
|
||||
// audio.
|
||||
int usedBytes = avcodec_encode_audio(fContext, fChunkBuffer,
|
||||
bufferSize, reinterpret_cast<const short*>(buffer));
|
||||
|
||||
if (usedBytes < 0) {
|
||||
TRACE(" avcodec_encode_video() failed: %d\n", usedBytes);
|
||||
return B_ERROR;
|
||||
}
|
||||
|
||||
// Maybe we need to use this PTS to calculate start_time:
|
||||
if (fContext->coded_frame->pts != kNoPTSValue) {
|
||||
TRACE(" codec frame PTS: %lld (codec time_base: %d/%d)\n",
|
||||
fContext->coded_frame->pts, fContext->time_base.num,
|
||||
fContext->time_base.den);
|
||||
} else {
|
||||
TRACE(" codec frame PTS: N/A (codec time_base: %d/%d)\n",
|
||||
fContext->time_base.num, fContext->time_base.den);
|
||||
}
|
||||
|
||||
// Setup media_encode_info, most important is the time stamp.
|
||||
info->start_time = (bigtime_t)(fFramesWritten * 1000000LL
|
||||
/ fInputFormat.u.raw_audio.frame_rate);
|
||||
|
||||
// Write the chunk
|
||||
status_t ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
||||
if (ret != B_OK) {
|
||||
TRACE(" error writing chunk: %s\n", strerror(ret));
|
||||
return ret;
|
||||
}
|
||||
|
||||
fFramesWritten += frameCount;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
||||
media_encode_info* info)
|
||||
|
@ -450,8 +471,10 @@ AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
|||
|
||||
// Write the chunk
|
||||
ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
||||
if (ret != B_OK)
|
||||
if (ret != B_OK) {
|
||||
TRACE(" error writing chunk: %s\n", strerror(ret));
|
||||
break;
|
||||
}
|
||||
|
||||
// Skip to the next frame (but usually, there is only one to encode
|
||||
// for video).
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
extern "C" {
|
||||
#include "avcodec.h"
|
||||
#include "swscale.h"
|
||||
#include "libavutil/fifo.h"
|
||||
}
|
||||
|
||||
#include "EncoderPlugin.h"
|
||||
|
@ -36,10 +37,17 @@ public:
|
|||
virtual status_t Encode(const void* buffer, int64 frameCount,
|
||||
media_encode_info* info);
|
||||
|
||||
// TODO: Turns out we need Flush() after all. We buffer encoded audio
|
||||
// in a FIFO, since the user suggested buffer size may not fit the
|
||||
// codec buffer size.
|
||||
|
||||
private:
|
||||
status_t _EncodeAudio(const void* buffer,
|
||||
int64 frameCount,
|
||||
media_encode_info* info);
|
||||
status_t _EncodeAudio(const uint8* buffer,
|
||||
size_t bufferSize, int64 frameCount,
|
||||
media_encode_info* info);
|
||||
|
||||
status_t _EncodeVideo(const void* buffer,
|
||||
int64 frameCount,
|
||||
|
@ -54,11 +62,15 @@ private:
|
|||
AVCodecContext* fContext;
|
||||
bool fCodecInitDone;
|
||||
|
||||
// For video (color space conversion):
|
||||
AVPicture fSrcFrame;
|
||||
AVPicture fDstFrame;
|
||||
AVFrame* fFrame;
|
||||
SwsContext* fSwsContext;
|
||||
|
||||
// For encoded audio:
|
||||
AVFifoBuffer fAudioFifo;
|
||||
|
||||
int64 fFramesWritten;
|
||||
|
||||
uint8* fChunkBuffer;
|
||||
|
|
|
@ -103,7 +103,7 @@ status_t
|
|||
AVFormatWriter::StreamCookie::Init(const media_format* format,
|
||||
const media_codec_info* codecInfo)
|
||||
{
|
||||
TRACE("AVFormatWriter::StreamCookie::Init() (Yes, New)\n");
|
||||
TRACE("AVFormatWriter::StreamCookie::Init()\n");
|
||||
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
|
|
|
@ -59,6 +59,18 @@ const EncoderDescription gEncoderTable[] = {
|
|||
B_ANY_FORMAT_FAMILY,
|
||||
B_MEDIA_RAW_AUDIO,
|
||||
B_MEDIA_ENCODED_AUDIO
|
||||
},
|
||||
{
|
||||
{
|
||||
"Dolby Digital (AC-3)",
|
||||
"ac3",
|
||||
0,
|
||||
CODEC_ID_AC3,
|
||||
{ 0 }
|
||||
},
|
||||
B_ANY_FORMAT_FAMILY,
|
||||
B_MEDIA_RAW_AUDIO,
|
||||
B_MEDIA_ENCODED_AUDIO
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -431,7 +431,7 @@
|
|||
#define CONFIG_WMV2_ENCODER 0
|
||||
#define CONFIG_ZLIB_ENCODER 0
|
||||
#define CONFIG_ZMBV_ENCODER 0
|
||||
#define CONFIG_AC3_ENCODER 0
|
||||
#define CONFIG_AC3_ENCODER 1
|
||||
#define CONFIG_ALAC_ENCODER 0
|
||||
#define CONFIG_FLAC_ENCODER 0
|
||||
#define CONFIG_MP2_ENCODER 0
|
||||
|
|
|
@ -29,6 +29,7 @@ StaticLibrary libavcodec.a :
|
|||
ac3_parser.c
|
||||
ac3dec.c
|
||||
ac3dec_data.c
|
||||
ac3enc.c
|
||||
ac3tab.c
|
||||
acelp_filters.c
|
||||
acelp_pitch_delay.c
|
||||
|
|
Loading…
Reference in New Issue