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:
Stephan Aßmus
2009-08-03 22:53:52 +00:00
parent 6ca5e0f9fa
commit 6e567425c6
6 changed files with 105 additions and 57 deletions
@@ -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
} }
}; };
+1 -1
View File
@@ -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