* 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 "AVCodecEncoder.h"
|
||||||
|
|
||||||
|
#include <new>
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "rational.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#undef TRACE
|
#undef TRACE
|
||||||
#define TRACE_AV_CODEC_ENCODER
|
#define TRACE_AV_CODEC_ENCODER
|
||||||
@@ -18,17 +24,40 @@
|
|||||||
#endif
|
#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");
|
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()
|
AVCodecEncoder::~AVCodecEncoder()
|
||||||
{
|
{
|
||||||
TRACE("AVCodecEncoder::~AVCodecEncoder()\n");
|
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");
|
TRACE("AVCodecEncoder::SetUp()\n");
|
||||||
|
|
||||||
|
if (fContext == NULL || fCodec == NULL)
|
||||||
|
return B_NO_INIT;
|
||||||
|
|
||||||
if (inputFormat == NULL)
|
if (inputFormat == NULL)
|
||||||
return B_BAD_VALUE;
|
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);
|
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;
|
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>
|
#include <MediaFormats.h>
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "avcodec.h"
|
||||||
|
}
|
||||||
|
|
||||||
#include "EncoderPlugin.h"
|
#include "EncoderPlugin.h"
|
||||||
|
|
||||||
|
|
||||||
class AVCodecEncoder : public Encoder {
|
class AVCodecEncoder : public Encoder {
|
||||||
public:
|
public:
|
||||||
AVCodecEncoder(const char* shortName);
|
AVCodecEncoder(uint32 codecID);
|
||||||
|
|
||||||
virtual ~AVCodecEncoder();
|
virtual ~AVCodecEncoder();
|
||||||
|
|
||||||
@@ -32,6 +36,29 @@ public:
|
|||||||
media_encode_info* info);
|
media_encode_info* info);
|
||||||
|
|
||||||
private:
|
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
|
#endif // AVCODEC_ENCODER_H
|
||||||
|
|||||||
@@ -6,14 +6,18 @@
|
|||||||
|
|
||||||
#include "EncoderTable.h"
|
#include "EncoderTable.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include "avcodec.h"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
const EncoderDescription gEncoderTable[] = {
|
const EncoderDescription gEncoderTable[] = {
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"MPEG2 Video",
|
"MPEG4 Video",
|
||||||
"mpeg2video",
|
"mpeg4",
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
|
CODEC_ID_MPEG4,
|
||||||
{ 0 }
|
{ 0 }
|
||||||
},
|
},
|
||||||
B_ANY_FORMAT_FAMILY,
|
B_ANY_FORMAT_FAMILY,
|
||||||
@@ -22,10 +26,10 @@ const EncoderDescription gEncoderTable[] = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
"WAV",
|
"MP3 Audio",
|
||||||
"wav",
|
"mp3",
|
||||||
0,
|
|
||||||
0,
|
0,
|
||||||
|
CODEC_ID_MP3,
|
||||||
{ 0 }
|
{ 0 }
|
||||||
},
|
},
|
||||||
B_ANY_FORMAT_FAMILY,
|
B_ANY_FORMAT_FAMILY,
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ FFmpegPlugin::GetSupportedFileFormats(const media_file_format** _fileFormats,
|
|||||||
Encoder*
|
Encoder*
|
||||||
FFmpegPlugin::NewEncoder(const media_codec_info& codecInfo)
|
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_OK;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AddOnManager::GetReaders(xfer_entry_ref* outRefs, int32* outCount,
|
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) {
|
if (info->internalID == (uint32)id) {
|
||||||
printf("AddOnManager::GetEncoderForFormat: found encoder %s for "
|
printf("AddOnManager::GetEncoderForFormat: found encoder %s for "
|
||||||
"id %ld\n", info->ref.name, id);
|
"id %ld\n", info->ref.name, id);
|
||||||
|
|
||||||
*_encoderRef = info->ref;
|
*_encoderRef = info->ref;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
@@ -161,9 +161,9 @@ AddOnManager::GetEncoder(xfer_entry_ref* _encoderRef, int32 id)
|
|||||||
printf("AddOnManager::GetEncoderForFormat: failed to find encoder for id "
|
printf("AddOnManager::GetEncoderForFormat: failed to find encoder for id "
|
||||||
"%ld\n", id);
|
"%ld\n", id);
|
||||||
|
|
||||||
return B_ENTRY_NOT_FOUND;
|
return B_ENTRY_NOT_FOUND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AddOnManager::GetWriter(xfer_entry_ref* _ref, uint32 internalID)
|
AddOnManager::GetWriter(xfer_entry_ref* _ref, uint32 internalID)
|
||||||
@@ -275,7 +275,7 @@ AddOnManager::_RegisterAddOn(BEntry& entry)
|
|||||||
_RegisterEncoder(encoder, ref);
|
_RegisterEncoder(encoder, ref);
|
||||||
|
|
||||||
delete plugin;
|
delete plugin;
|
||||||
|
|
||||||
return B_OK;
|
return B_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,7 +347,7 @@ AddOnManager::_RegisterAddOns()
|
|||||||
|
|
||||||
if (find_directory(directories[i], &path) == B_OK
|
if (find_directory(directories[i], &path) == B_OK
|
||||||
&& path.Append("media/plugins") == 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) {
|
&& directory.GetNodeRef(&nref) == B_OK) {
|
||||||
fHandler->AddDirectory(&nref);
|
fHandler->AddDirectory(&nref);
|
||||||
}
|
}
|
||||||
@@ -475,7 +475,6 @@ AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref)
|
|||||||
info.internalID = fNextEncoderCodecInfoID++;
|
info.internalID = fNextEncoderCodecInfoID++;
|
||||||
|
|
||||||
int32 cookie = 0;
|
int32 cookie = 0;
|
||||||
int32 subID = 0;
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
memset(&info.codecInfo, 0, sizeof(media_codec_info));
|
memset(&info.codecInfo, 0, sizeof(media_codec_info));
|
||||||
@@ -487,7 +486,9 @@ AddOnManager::_RegisterEncoder(EncoderPlugin* plugin, const entry_ref& ref)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
info.codecInfo.id = info.internalID;
|
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))
|
if (!fEncoderList.Insert(info))
|
||||||
break;
|
break;
|
||||||
|
|||||||
Reference in New Issue
Block a user