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:
@@ -9,6 +9,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include "rational.h"
|
#include "rational.h"
|
||||||
@@ -46,9 +47,11 @@ AVCodecEncoder::AVCodecEncoder(uint32 codecID)
|
|||||||
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
|
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
|
||||||
|
|
||||||
fCodec = avcodec_find_encoder((enum CodecID)codecID);
|
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));
|
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;
|
size_t bufferSize = frameCount * inputFrameSize;
|
||||||
bufferSize = min_c(bufferSize, kDefaultChunkBufferSize);
|
bufferSize = min_c(bufferSize, kDefaultChunkBufferSize);
|
||||||
|
|
||||||
while (frameCount > 0) {
|
if (fContext->frame_size > 1) {
|
||||||
if (frameCount < fContext->frame_size) {
|
// Encoded audio. Things work differently from raw audio. We need
|
||||||
TRACE(" ERROR: too few frames left! (left: %lld, needed: %d)\n",
|
// the fAudioFifo to pipe data.
|
||||||
frameCount, fContext->frame_size);
|
if (av_fifo_realloc2(&fAudioFifo,
|
||||||
// TODO: Handle this some way. Maybe use an av_fifo to buffer data?
|
av_fifo_size(&fAudioFifo) + bufferSize) < 0) {
|
||||||
return B_ERROR;
|
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;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
int chunkFrames = fContext->frame_size;
|
// Raw audio. The number of bytes returned from avcodec_encode_audio()
|
||||||
|
// is always the same as the number of input bytes.
|
||||||
TRACE(" frames left: %lld, chunk frames: %d\n",
|
return _EncodeAudio(buffer, bufferSize, frameCount,
|
||||||
frameCount, chunkFrames);
|
info);
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return ret;
|
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
|
status_t
|
||||||
AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
||||||
media_encode_info* info)
|
media_encode_info* info)
|
||||||
@@ -450,8 +471,10 @@ AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
|||||||
|
|
||||||
// Write the chunk
|
// Write the chunk
|
||||||
ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
||||||
if (ret != B_OK)
|
if (ret != B_OK) {
|
||||||
|
TRACE(" error writing chunk: %s\n", strerror(ret));
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip to the next frame (but usually, there is only one to encode
|
// Skip to the next frame (but usually, there is only one to encode
|
||||||
// for video).
|
// for video).
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
extern "C" {
|
extern "C" {
|
||||||
#include "avcodec.h"
|
#include "avcodec.h"
|
||||||
#include "swscale.h"
|
#include "swscale.h"
|
||||||
|
#include "libavutil/fifo.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "EncoderPlugin.h"
|
#include "EncoderPlugin.h"
|
||||||
@@ -36,10 +37,17 @@ public:
|
|||||||
virtual status_t Encode(const void* buffer, int64 frameCount,
|
virtual status_t Encode(const void* buffer, int64 frameCount,
|
||||||
media_encode_info* info);
|
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:
|
private:
|
||||||
status_t _EncodeAudio(const void* buffer,
|
status_t _EncodeAudio(const void* buffer,
|
||||||
int64 frameCount,
|
int64 frameCount,
|
||||||
media_encode_info* info);
|
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,
|
status_t _EncodeVideo(const void* buffer,
|
||||||
int64 frameCount,
|
int64 frameCount,
|
||||||
@@ -54,11 +62,15 @@ private:
|
|||||||
AVCodecContext* fContext;
|
AVCodecContext* fContext;
|
||||||
bool fCodecInitDone;
|
bool fCodecInitDone;
|
||||||
|
|
||||||
|
// For video (color space conversion):
|
||||||
AVPicture fSrcFrame;
|
AVPicture fSrcFrame;
|
||||||
AVPicture fDstFrame;
|
AVPicture fDstFrame;
|
||||||
AVFrame* fFrame;
|
AVFrame* fFrame;
|
||||||
SwsContext* fSwsContext;
|
SwsContext* fSwsContext;
|
||||||
|
|
||||||
|
// For encoded audio:
|
||||||
|
AVFifoBuffer fAudioFifo;
|
||||||
|
|
||||||
int64 fFramesWritten;
|
int64 fFramesWritten;
|
||||||
|
|
||||||
uint8* fChunkBuffer;
|
uint8* fChunkBuffer;
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ status_t
|
|||||||
AVFormatWriter::StreamCookie::Init(const media_format* format,
|
AVFormatWriter::StreamCookie::Init(const media_format* format,
|
||||||
const media_codec_info* codecInfo)
|
const media_codec_info* codecInfo)
|
||||||
{
|
{
|
||||||
TRACE("AVFormatWriter::StreamCookie::Init() (Yes, New)\n");
|
TRACE("AVFormatWriter::StreamCookie::Init()\n");
|
||||||
|
|
||||||
BAutolock _(fStreamLock);
|
BAutolock _(fStreamLock);
|
||||||
|
|
||||||
|
|||||||
@@ -59,6 +59,18 @@ const EncoderDescription gEncoderTable[] = {
|
|||||||
B_ANY_FORMAT_FAMILY,
|
B_ANY_FORMAT_FAMILY,
|
||||||
B_MEDIA_RAW_AUDIO,
|
B_MEDIA_RAW_AUDIO,
|
||||||
B_MEDIA_ENCODED_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_WMV2_ENCODER 0
|
||||||
#define CONFIG_ZLIB_ENCODER 0
|
#define CONFIG_ZLIB_ENCODER 0
|
||||||
#define CONFIG_ZMBV_ENCODER 0
|
#define CONFIG_ZMBV_ENCODER 0
|
||||||
#define CONFIG_AC3_ENCODER 0
|
#define CONFIG_AC3_ENCODER 1
|
||||||
#define CONFIG_ALAC_ENCODER 0
|
#define CONFIG_ALAC_ENCODER 0
|
||||||
#define CONFIG_FLAC_ENCODER 0
|
#define CONFIG_FLAC_ENCODER 0
|
||||||
#define CONFIG_MP2_ENCODER 0
|
#define CONFIG_MP2_ENCODER 0
|
||||||
|
|||||||
@@ -29,6 +29,7 @@ StaticLibrary libavcodec.a :
|
|||||||
ac3_parser.c
|
ac3_parser.c
|
||||||
ac3dec.c
|
ac3dec.c
|
||||||
ac3dec_data.c
|
ac3dec_data.c
|
||||||
|
ac3enc.c
|
||||||
ac3tab.c
|
ac3tab.c
|
||||||
acelp_filters.c
|
acelp_filters.c
|
||||||
acelp_pitch_delay.c
|
acelp_pitch_delay.c
|
||||||
|
|||||||
Reference in New Issue
Block a user