* Let the Encoders use the media_codec_info.sub_id field for their own purposes.

* Implemented some of AVCodecEncoder. Maybe video encoding already works, but
  we don't know until the AVFormatWriter is more than just stubs... but I doubt
  it. :-)


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32016 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus
2009-07-31 13:06:34 +00:00
parent 3ae83fe3c7
commit 313fedacc1
5 changed files with 181 additions and 20 deletions
@@ -6,8 +6,14 @@
#include "AVCodecEncoder.h"
#include <new>
#include <stdio.h>
extern "C" {
#include "rational.h"
}
#undef TRACE
#define TRACE_AV_CODEC_ENCODER
@@ -18,17 +24,40 @@
#endif
AVCodecEncoder::AVCodecEncoder(const char* shortName)
static const size_t kDefaultChunkBufferSize = FF_MIN_BUFFER_SIZE;
AVCodecEncoder::AVCodecEncoder(uint32 codecID)
:
Encoder()
Encoder(),
fCodec(NULL),
fContext(avcodec_alloc_context()),
fInputPicture(avcodec_alloc_frame()),
// fOutputPicture(avcodec_alloc_frame()),
fCodecInitDone(false),
fChunkBuffer(new(std::nothrow) uint8[kDefaultChunkBufferSize])
{
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
fCodec = avcodec_find_encoder((enum CodecID)codecID);
TRACE(" found AVCodec: %p\n", fCodec);
memset(&fInputFormat, 0, sizeof(media_format));
}
AVCodecEncoder::~AVCodecEncoder()
{
TRACE("AVCodecEncoder::~AVCodecEncoder()\n");
if (fCodecInitDone)
avcodec_close(fContext);
// free(fOutputPicture);
free(fInputPicture);
free(fContext);
delete[] fChunkBuffer;
}
@@ -56,10 +85,48 @@ AVCodecEncoder::SetUp(const media_format* inputFormat)
{
TRACE("AVCodecEncoder::SetUp()\n");
if (fContext == NULL || fCodec == NULL)
return B_NO_INIT;
if (inputFormat == NULL)
return B_BAD_VALUE;
return B_NOT_SUPPORTED;
fInputFormat = *inputFormat;
if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
fContext->width = fInputFormat.u.raw_video.display.line_width;
fContext->height = fInputFormat.u.raw_video.display.line_count;
// fContext->gop_size = 12;
fContext->pix_fmt = PIX_FMT_BGR32;
// fContext->rate_emu = 0;
// TODO: Setup rate control:
// fContext->rc_eq = NULL;
// fContext->rc_max_rate = 0;
// fContext->rc_min_rate = 0;
fContext->sample_aspect_ratio.num
= fInputFormat.u.raw_video.pixel_width_aspect;
fContext->sample_aspect_ratio.den
= fInputFormat.u.raw_video.pixel_height_aspect;
if (fContext->sample_aspect_ratio.num == 0
|| fContext->sample_aspect_ratio.den == 0) {
av_reduce(&fContext->sample_aspect_ratio.num,
&fContext->sample_aspect_ratio.den, fContext->width,
fContext->height, 256);
}
// TODO: This should already happen in AcceptFormat()
fInputFormat.u.raw_video.display.bytes_per_row = fContext->width * 4;
} else {
return B_NOT_SUPPORTED;
}
// Open the codec
int result = avcodec_open(fContext, fCodec);
fCodecInitDone = (result >= 0);
TRACE(" avcodec_open(): %d\n", result);
return fCodecInitDone ? B_OK : B_ERROR;
}
@@ -87,5 +154,67 @@ AVCodecEncoder::Encode(const void* buffer, int64 frameCount,
{
TRACE("AVCodecEncoder::Encode(%p, %lld, %p)\n", buffer, frameCount, info);
if (fInputFormat.type == B_MEDIA_RAW_AUDIO)
return _EncodeAudio(buffer, frameCount, info);
else if (fInputFormat.type == B_MEDIA_RAW_VIDEO)
return _EncodeVideo(buffer, frameCount, info);
else
return B_NO_INIT;
}
// #pragma mark -
status_t
AVCodecEncoder::_EncodeAudio(const void* buffer, int64 frameCount,
media_encode_info* info)
{
TRACE("AVCodecEncoder::_EncodeAudio(%p, %lld, %p)\n", buffer, frameCount,
info);
return B_NOT_SUPPORTED;
}
status_t
AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
media_encode_info* info)
{
TRACE("AVCodecEncoder::_EncodeVideo(%p, %lld, %p)\n", buffer, frameCount,
info);
if (fChunkBuffer == NULL)
return B_NO_MEMORY;
status_t ret = B_OK;
while (frameCount > 0) {
size_t bpr = fInputFormat.u.raw_video.display.bytes_per_row;
size_t bufferSize = fInputFormat.u.raw_video.display.line_count * bpr;
fInputPicture->data[0] = (uint8_t*)buffer;
fInputPicture->linesize[0] = bpr;
int usedBytes = avcodec_encode_video(fContext, fChunkBuffer,
kDefaultChunkBufferSize, fInputPicture);
if (usedBytes < 0) {
TRACE(" avcodec_encode_video() failed: %d\n", usedBytes);
return B_ERROR;
}
// Write the chunk
ret = WriteChunk(fChunkBuffer, usedBytes, info);
if (ret != B_OK)
break;
// Skip to the next frame (but usually, there is only one to encode
// for video).
frameCount--;
buffer = (const void*)((const uint8*)buffer + bufferSize);
}
return ret;
}
@@ -8,12 +8,16 @@
#include <MediaFormats.h>
extern "C" {
#include "avcodec.h"
}
#include "EncoderPlugin.h"
class AVCodecEncoder : public Encoder {
public:
AVCodecEncoder(const char* shortName);
AVCodecEncoder(uint32 codecID);
virtual ~AVCodecEncoder();
@@ -32,6 +36,29 @@ public:
media_encode_info* info);
private:
status_t _EncodeAudio(const void* buffer,
int64 frameCount,
media_encode_info* info);
status_t _EncodeVideo(const void* buffer,
int64 frameCount,
media_encode_info* info);
private:
media_format fInputFormat;
// FFmpeg related members
// TODO: Refactor common base class from AVCodec[De|En]Coder!
AVCodec* fCodec;
AVCodecContext* fContext;
AVFrame* fInputPicture;
// AVFrame* fOutputPicture;
uint32 fAVCodecID;
bool fCodecInitDone;
uint8* fChunkBuffer;
};
#endif // AVCODEC_ENCODER_H
@@ -6,14 +6,18 @@
#include "EncoderTable.h"
extern "C" {
#include "avcodec.h"
}
const EncoderDescription gEncoderTable[] = {
{
{
"MPEG2 Video",
"mpeg2video",
0,
"MPEG4 Video",
"mpeg4",
0,
CODEC_ID_MPEG4,
{ 0 }
},
B_ANY_FORMAT_FAMILY,
@@ -22,10 +26,10 @@ const EncoderDescription gEncoderTable[] = {
},
{
{
"WAV",
"wav",
0,
"MP3 Audio",
"mp3",
0,
CODEC_ID_MP3,
{ 0 }
},
B_ANY_FORMAT_FAMILY,
@@ -134,7 +134,7 @@ FFmpegPlugin::GetSupportedFileFormats(const media_file_format** _fileFormats,
Encoder*
FFmpegPlugin::NewEncoder(const media_codec_info& codecInfo)
{
return new(std::nothrow)AVCodecEncoder(codecInfo.short_name);
return new(std::nothrow)AVCodecEncoder(codecInfo.sub_id);
}
+10 -9
View File
@@ -120,9 +120,9 @@ AddOnManager::GetDecoderForFormat(xfer_entry_ref* _decoderRef,
return B_OK;
}
}
return B_ENTRY_NOT_FOUND;
return B_ENTRY_NOT_FOUND;
}
status_t
AddOnManager::GetReaders(xfer_entry_ref* outRefs, int32* outCount,
@@ -152,7 +152,7 @@ AddOnManager::GetEncoder(xfer_entry_ref* _encoderRef, int32 id)
if (info->internalID == (uint32)id) {
printf("AddOnManager::GetEncoderForFormat: found encoder %s for "
"id %ld\n", info->ref.name, id);
*_encoderRef = info->ref;
return B_OK;
}
@@ -161,9 +161,9 @@ AddOnManager::GetEncoder(xfer_entry_ref* _encoderRef, int32 id)
printf("AddOnManager::GetEncoderForFormat: failed to find encoder for id "
"%ld\n", id);
return B_ENTRY_NOT_FOUND;
return B_ENTRY_NOT_FOUND;
}
status_t
AddOnManager::GetWriter(xfer_entry_ref* _ref, uint32 internalID)
@@ -275,7 +275,7 @@ AddOnManager::_RegisterAddOn(BEntry& entry)
_RegisterEncoder(encoder, ref);
delete plugin;
return B_OK;
}
@@ -347,7 +347,7 @@ AddOnManager::_RegisterAddOns()
if (find_directory(directories[i], &path) == B_OK
&& path.Append("media/plugins") == B_OK
&& directory.SetTo(path.Path()) == B_OK
&& directory.SetTo(path.Path()) == B_OK
&& directory.GetNodeRef(&nref) == B_OK) {
fHandler->AddDirectory(&nref);
}
@@ -475,7 +475,6 @@ AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref)
info.internalID = fNextEncoderCodecInfoID++;
int32 cookie = 0;
int32 subID = 0;
while (true) {
memset(&info.codecInfo, 0, sizeof(media_codec_info));
@@ -487,7 +486,9 @@ AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref)
break;
}
info.codecInfo.id = info.internalID;
info.codecInfo.sub_id = subID++;
// NOTE: info.codecInfo.sub_id is for private use by the Encoder,
// we don't touch it, but it is maintained and passed back to the
// EncoderPlugin in NewEncoder(media_codec_info).
if (!fEncoderList.Insert(info))
break;