* 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:
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user