Implemented audio track encoding. There is something wrong with the PTS
generation for the packets and how I set the time_base in the AVStream and AVStream->codec structures. This results in the audio streams of the written files to report a much too long duration. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@32064 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -34,9 +34,13 @@ AVCodecEncoder::AVCodecEncoder(uint32 codecID)
|
|||||||
Encoder(),
|
Encoder(),
|
||||||
fCodec(NULL),
|
fCodec(NULL),
|
||||||
fContext(avcodec_alloc_context()),
|
fContext(avcodec_alloc_context()),
|
||||||
|
fCodecInitDone(false),
|
||||||
|
|
||||||
fFrame(avcodec_alloc_frame()),
|
fFrame(avcodec_alloc_frame()),
|
||||||
fSwsContext(NULL),
|
fSwsContext(NULL),
|
||||||
fCodecInitDone(false),
|
|
||||||
|
fFramesWritten(0),
|
||||||
|
|
||||||
fChunkBuffer(new(std::nothrow) uint8[kDefaultChunkBufferSize])
|
fChunkBuffer(new(std::nothrow) uint8[kDefaultChunkBufferSize])
|
||||||
{
|
{
|
||||||
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
|
TRACE("AVCodecEncoder::AVCodecEncoder()\n");
|
||||||
@@ -110,7 +114,13 @@ AVCodecEncoder::SetUp(const media_format* inputFormat)
|
|||||||
if (inputFormat == NULL)
|
if (inputFormat == NULL)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (fCodecInitDone) {
|
||||||
|
fCodecInitDone = false;
|
||||||
|
avcodec_close(fContext);
|
||||||
|
}
|
||||||
|
|
||||||
fInputFormat = *inputFormat;
|
fInputFormat = *inputFormat;
|
||||||
|
fFramesWritten = 0;
|
||||||
|
|
||||||
if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
|
if (fInputFormat.type == B_MEDIA_RAW_VIDEO) {
|
||||||
// frame rate
|
// frame rate
|
||||||
@@ -167,6 +177,68 @@ AVCodecEncoder::SetUp(const media_format* inputFormat)
|
|||||||
PIX_FMT_RGB32, fContext->width, fContext->height,
|
PIX_FMT_RGB32, fContext->width, fContext->height,
|
||||||
fContext->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
|
fContext->pix_fmt, SWS_BICUBIC, NULL, NULL, NULL);
|
||||||
|
|
||||||
|
} else if (fInputFormat.type == B_MEDIA_RAW_AUDIO) {
|
||||||
|
// frame rate
|
||||||
|
fContext->sample_rate = (int)fInputFormat.u.raw_audio.frame_rate;
|
||||||
|
fContext->time_base.den = (int)fInputFormat.u.raw_audio.frame_rate;
|
||||||
|
fContext->time_base.num = 1;
|
||||||
|
// channels
|
||||||
|
fContext->channels = fInputFormat.u.raw_audio.channel_count;
|
||||||
|
switch (fInputFormat.u.raw_audio.format) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fContext->sample_fmt = SAMPLE_FMT_FLT;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fContext->sample_fmt = SAMPLE_FMT_DBL;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fContext->sample_fmt = SAMPLE_FMT_S32;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fContext->sample_fmt = SAMPLE_FMT_S16;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fContext->sample_fmt = SAMPLE_FMT_U8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
default:
|
||||||
|
return B_MEDIA_BAD_FORMAT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (fInputFormat.u.raw_audio.channel_mask == 0) {
|
||||||
|
// guess the channel mask...
|
||||||
|
switch (fInputFormat.u.raw_audio.channel_count) {
|
||||||
|
default:
|
||||||
|
case 2:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_STEREO;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_MONO;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_SURROUND;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_QUAD;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_5POINT0;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_5POINT1;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_7POINT1;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
fContext->channel_layout = CH_LAYOUT_7POINT1_WIDE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The bits match 1:1 for media_multi_channels and FFmpeg defines.
|
||||||
|
fContext->channel_layout = fInputFormat.u.raw_audio.channel_mask;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
return B_NOT_SUPPORTED;
|
return B_NOT_SUPPORTED;
|
||||||
}
|
}
|
||||||
@@ -221,13 +293,80 @@ AVCodecEncoder::Encode(const void* buffer, int64 frameCount,
|
|||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
AVCodecEncoder::_EncodeAudio(const void* buffer, int64 frameCount,
|
AVCodecEncoder::_EncodeAudio(const void* _buffer, int64 frameCount,
|
||||||
media_encode_info* info)
|
media_encode_info* info)
|
||||||
{
|
{
|
||||||
TRACE("AVCodecEncoder::_EncodeAudio(%p, %lld, %p)\n", buffer, frameCount,
|
TRACE("AVCodecEncoder::_EncodeAudio(%p, %lld, %p)\n", _buffer, frameCount,
|
||||||
info);
|
info);
|
||||||
|
|
||||||
return B_NOT_SUPPORTED;
|
if (fChunkBuffer == NULL)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
status_t ret = B_OK;
|
||||||
|
|
||||||
|
const uint8* buffer = reinterpret_cast<const uint8*>(_buffer);
|
||||||
|
|
||||||
|
size_t inputSampleSize = fInputFormat.u.raw_audio.format
|
||||||
|
& media_raw_audio_format::B_AUDIO_SIZE_MASK;
|
||||||
|
size_t inputFrameSize = inputSampleSize
|
||||||
|
* fInputFormat.u.raw_audio.channel_count;
|
||||||
|
|
||||||
|
size_t outSampleSize = av_get_bits_per_sample_format(
|
||||||
|
fContext->sample_fmt) / 8;
|
||||||
|
size_t outSize = outSampleSize * fContext->channels;
|
||||||
|
TRACE(" sampleSize: %ld/%ld, frameSize: %ld/%ld\n",
|
||||||
|
inputSampleSize, inputFrameSize, outSampleSize, outSize);
|
||||||
|
|
||||||
|
size_t bufferSize = frameCount * inputFrameSize;
|
||||||
|
bufferSize = min_c(bufferSize, kDefaultChunkBufferSize);
|
||||||
|
|
||||||
|
while (frameCount > 0) {
|
||||||
|
if (frameCount < fContext->frame_size) {
|
||||||
|
TRACE(" ERROR: too few frames left! (left: %lld, needed: %d)\n",
|
||||||
|
frameCount, fContext->frame_size);
|
||||||
|
// TODO: Handle this some way. Maybe use an av_fifo to buffer data?
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
int chunkFrames = fContext->frame_size;
|
||||||
|
|
||||||
|
TRACE(" frames left: %lld, chunk frames: %d\n",
|
||||||
|
frameCount, chunkFrames);
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -268,6 +407,10 @@ AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
|||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Setup media_encode_info, most important is the time stamp.
|
||||||
|
info->start_time = (bigtime_t)(fFramesWritten * 1000000LL
|
||||||
|
/ fInputFormat.u.raw_video.field_rate);
|
||||||
|
|
||||||
// Write the chunk
|
// Write the chunk
|
||||||
ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
ret = WriteChunk(fChunkBuffer, usedBytes, info);
|
||||||
if (ret != B_OK)
|
if (ret != B_OK)
|
||||||
@@ -276,6 +419,7 @@ AVCodecEncoder::_EncodeVideo(const void* buffer, int64 frameCount,
|
|||||||
// 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).
|
||||||
frameCount--;
|
frameCount--;
|
||||||
|
fFramesWritten++;
|
||||||
buffer = (const void*)((const uint8*)buffer + bufferSize);
|
buffer = (const void*)((const uint8*)buffer + bufferSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -52,14 +52,14 @@ private:
|
|||||||
// TODO: Refactor common base class from AVCodec[De|En]Coder!
|
// TODO: Refactor common base class from AVCodec[De|En]Coder!
|
||||||
AVCodec* fCodec;
|
AVCodec* fCodec;
|
||||||
AVCodecContext* fContext;
|
AVCodecContext* fContext;
|
||||||
|
bool fCodecInitDone;
|
||||||
|
|
||||||
AVPicture fSrcFrame;
|
AVPicture fSrcFrame;
|
||||||
AVPicture fDstFrame;
|
AVPicture fDstFrame;
|
||||||
AVFrame* fFrame;
|
AVFrame* fFrame;
|
||||||
SwsContext* fSwsContext;
|
SwsContext* fSwsContext;
|
||||||
|
|
||||||
uint32 fAVCodecID;
|
int64 fFramesWritten;
|
||||||
|
|
||||||
bool fCodecInitDone;
|
|
||||||
|
|
||||||
uint8* fChunkBuffer;
|
uint8* fChunkBuffer;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ extern "C" {
|
|||||||
#include "gfx_util.h"
|
#include "gfx_util.h"
|
||||||
|
|
||||||
|
|
||||||
//#define TRACE_AVFORMAT_READER
|
#define TRACE_AVFORMAT_READER
|
||||||
#ifdef TRACE_AVFORMAT_READER
|
#ifdef TRACE_AVFORMAT_READER
|
||||||
# define TRACE printf
|
# define TRACE printf
|
||||||
# define TRACE_IO(a...)
|
# define TRACE_IO(a...)
|
||||||
@@ -674,7 +674,7 @@ AVFormatReader::StreamCookie::GetStreamInfo(int64* frameCount,
|
|||||||
*duration = (bigtime_t)(1000000LL * fStream->duration
|
*duration = (bigtime_t)(1000000LL * fStream->duration
|
||||||
* fStream->time_base.num / fStream->time_base.den);
|
* fStream->time_base.num / fStream->time_base.den);
|
||||||
TRACE(" stream duration: %lld, time_base %.4f (%d/%d)\n",
|
TRACE(" stream duration: %lld, time_base %.4f (%d/%d)\n",
|
||||||
*duration, av_q2d(fStream->time_base),
|
fStream->duration, av_q2d(fStream->time_base),
|
||||||
fStream->time_base.num, fStream->time_base.den);
|
fStream->time_base.num, fStream->time_base.den);
|
||||||
} else if ((int64)fContext->duration != kNoPTSValue) {
|
} else if ((int64)fContext->duration != kNoPTSValue) {
|
||||||
*duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE);
|
*duration = (bigtime_t)(1000000LL * fContext->duration / AV_TIME_BASE);
|
||||||
@@ -844,6 +844,8 @@ AVFormatReader::StreamCookie::GetNextChunk(const void** chunkBuffer,
|
|||||||
mediaHeader->destination = -1;
|
mediaHeader->destination = -1;
|
||||||
mediaHeader->time_source = -1;
|
mediaHeader->time_source = -1;
|
||||||
mediaHeader->size_used = fPacket.size;
|
mediaHeader->size_used = fPacket.size;
|
||||||
|
//TRACE(" PTS: %lld (time_base.num: %d, .den: %d)\n",
|
||||||
|
//fPacket.pts, fStream->time_base.num, fStream->time_base.den);
|
||||||
mediaHeader->start_time = (bigtime_t)(1000000.0 * fPacket.pts
|
mediaHeader->start_time = (bigtime_t)(1000000.0 * fPacket.pts
|
||||||
/ av_q2d(fStream->time_base));
|
/ av_q2d(fStream->time_base));
|
||||||
mediaHeader->file_pos = fPacket.pos;
|
mediaHeader->file_pos = fPacket.pos;
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ extern "C" {
|
|||||||
#ifdef TRACE_AVFORMAT_WRITER
|
#ifdef TRACE_AVFORMAT_WRITER
|
||||||
# define TRACE printf
|
# define TRACE printf
|
||||||
# define TRACE_IO(a...)
|
# define TRACE_IO(a...)
|
||||||
# define TRACE_PACKET(a...)
|
# define TRACE_PACKET printf
|
||||||
#else
|
#else
|
||||||
# define TRACE(a...)
|
# define TRACE(a...)
|
||||||
# define TRACE_IO(a...)
|
# define TRACE_IO(a...)
|
||||||
@@ -75,6 +75,7 @@ private:
|
|||||||
// Since different threads may write to the target,
|
// Since different threads may write to the target,
|
||||||
// we need to protect the file position and I/O by a lock.
|
// we need to protect the file position and I/O by a lock.
|
||||||
BLocker* fStreamLock;
|
BLocker* fStreamLock;
|
||||||
|
int64 fChunksWritten;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -84,7 +85,8 @@ AVFormatWriter::StreamCookie::StreamCookie(AVFormatContext* context,
|
|||||||
:
|
:
|
||||||
fContext(context),
|
fContext(context),
|
||||||
fStream(NULL),
|
fStream(NULL),
|
||||||
fStreamLock(streamLock)
|
fStreamLock(streamLock),
|
||||||
|
fChunksWritten(0)
|
||||||
{
|
{
|
||||||
av_new_packet(&fPacket, 0);
|
av_new_packet(&fPacket, 0);
|
||||||
}
|
}
|
||||||
@@ -118,6 +120,10 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
|||||||
// frame rate
|
// frame rate
|
||||||
fStream->codec->time_base.den = (int)format->u.raw_video.field_rate;
|
fStream->codec->time_base.den = (int)format->u.raw_video.field_rate;
|
||||||
fStream->codec->time_base.num = 1;
|
fStream->codec->time_base.num = 1;
|
||||||
|
fStream->r_frame_rate.den = (int)format->u.raw_video.field_rate;
|
||||||
|
fStream->r_frame_rate.num = 1;
|
||||||
|
fStream->time_base.den = (int)format->u.raw_video.field_rate;
|
||||||
|
fStream->time_base.num = 1;
|
||||||
// video size
|
// video size
|
||||||
fStream->codec->width = format->u.raw_video.display.line_width;
|
fStream->codec->width = format->u.raw_video.display.line_width;
|
||||||
fStream->codec->height = format->u.raw_video.display.line_count;
|
fStream->codec->height = format->u.raw_video.display.line_count;
|
||||||
@@ -138,9 +144,75 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
|||||||
fStream->codec->pix_fmt = PIX_FMT_YUV420P;
|
fStream->codec->pix_fmt = PIX_FMT_YUV420P;
|
||||||
} else if (format->type == B_MEDIA_RAW_AUDIO) {
|
} else if (format->type == B_MEDIA_RAW_AUDIO) {
|
||||||
avcodec_get_context_defaults2(fStream->codec, CODEC_TYPE_AUDIO);
|
avcodec_get_context_defaults2(fStream->codec, CODEC_TYPE_AUDIO);
|
||||||
// TODO: ...
|
// channels
|
||||||
|
fStream->codec->channels = format->u.raw_audio.channel_count;
|
||||||
|
switch (format->u.raw_audio.format) {
|
||||||
|
case media_raw_audio_format::B_AUDIO_FLOAT:
|
||||||
|
fStream->codec->sample_fmt = SAMPLE_FMT_FLT;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_DOUBLE:
|
||||||
|
fStream->codec->sample_fmt = SAMPLE_FMT_DBL;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_INT:
|
||||||
|
fStream->codec->sample_fmt = SAMPLE_FMT_S32;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_SHORT:
|
||||||
|
fStream->codec->sample_fmt = SAMPLE_FMT_S16;
|
||||||
|
break;
|
||||||
|
case media_raw_audio_format::B_AUDIO_UCHAR:
|
||||||
|
fStream->codec->sample_fmt = SAMPLE_FMT_U8;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case media_raw_audio_format::B_AUDIO_CHAR:
|
||||||
|
default:
|
||||||
|
return B_MEDIA_BAD_FORMAT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (format->u.raw_audio.channel_mask == 0) {
|
||||||
|
// guess the channel mask...
|
||||||
|
switch (format->u.raw_audio.channel_count) {
|
||||||
|
default:
|
||||||
|
case 2:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_STEREO;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_MONO;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_SURROUND;
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_QUAD;
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_5POINT0;
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_5POINT1;
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_7POINT1;
|
||||||
|
break;
|
||||||
|
case 10:
|
||||||
|
fStream->codec->channel_layout = CH_LAYOUT_7POINT1_WIDE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// The bits match 1:1 for media_multi_channels and FFmpeg defines.
|
||||||
|
fStream->codec->channel_layout = format->u.raw_audio.channel_mask;
|
||||||
|
}
|
||||||
|
// frame rate
|
||||||
|
fStream->codec->sample_rate = (int)format->u.raw_audio.frame_rate;
|
||||||
|
fStream->codec->time_base.den = (int)format->u.raw_audio.frame_rate;
|
||||||
|
fStream->codec->time_base.num = 1;
|
||||||
|
fStream->time_base.den = (int)format->u.raw_audio.frame_rate;
|
||||||
|
fStream->time_base.num = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TRACE(" stream->time_base: (%d/%d), codec->time_base: (%d/%d))\n",
|
||||||
|
fStream->time_base.num, fStream->time_base.den,
|
||||||
|
fStream->codec->time_base.num, fStream->codec->time_base.den);
|
||||||
|
|
||||||
// TODO: This is a hack for now! Use avcodec_find_encoder_by_name()
|
// TODO: This is a hack for now! Use avcodec_find_encoder_by_name()
|
||||||
// or something similar...
|
// or something similar...
|
||||||
fStream->codec->codec_id = (CodecID)codecInfo->sub_id;
|
fStream->codec->codec_id = (CodecID)codecInfo->sub_id;
|
||||||
@@ -153,8 +225,8 @@ status_t
|
|||||||
AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
|
AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
|
||||||
size_t chunkSize, media_encode_info* encodeInfo)
|
size_t chunkSize, media_encode_info* encodeInfo)
|
||||||
{
|
{
|
||||||
TRACE_PACKET("AVFormatWriter::StreamCookie::WriteChunk(%p, %ld)\n",
|
TRACE_PACKET("AVFormatWriter::StreamCookie::WriteChunk(%p, %ld, "
|
||||||
chunkBuffer, chunkSize);
|
"start_time: %lld)\n", chunkBuffer, chunkSize, encodeInfo->start_time);
|
||||||
|
|
||||||
BAutolock _(fStreamLock);
|
BAutolock _(fStreamLock);
|
||||||
|
|
||||||
@@ -164,6 +236,19 @@ AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
|
|||||||
fPacket.data = const_cast<uint8_t*>((const uint8_t*)chunkBuffer);
|
fPacket.data = const_cast<uint8_t*>((const uint8_t*)chunkBuffer);
|
||||||
fPacket.size = chunkSize;
|
fPacket.size = chunkSize;
|
||||||
|
|
||||||
|
fPacket.pts = (encodeInfo->start_time
|
||||||
|
* fStream->time_base.den / fStream->time_base.num) / 1000000;
|
||||||
|
TRACE_PACKET(" PTS: %lld (stream->time_base: (%d/%d), "
|
||||||
|
"codec->time_base: (%d/%d))\n", fPacket.pts,
|
||||||
|
fStream->time_base.num, fStream->time_base.den,
|
||||||
|
fStream->codec->time_base.num, fStream->codec->time_base.den);
|
||||||
|
|
||||||
|
// From ffmpeg.c::do_audio_out():
|
||||||
|
// if (enc->coded_frame && enc->coded_frame->pts != AV_NOPTS_VALUE)
|
||||||
|
// fPacket.pts = av_rescale_q(enc->coded_frame->pts,
|
||||||
|
// enc->time_base, ost->st->time_base);
|
||||||
|
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
// TODO: Eventually, we need to write interleaved packets, but
|
// TODO: Eventually, we need to write interleaved packets, but
|
||||||
// maybe we are only supposed to use this if we have actually
|
// maybe we are only supposed to use this if we have actually
|
||||||
@@ -280,12 +365,27 @@ AVFormatWriter::CommitHeader()
|
|||||||
if (fHeaderWritten)
|
if (fHeaderWritten)
|
||||||
return B_NOT_ALLOWED;
|
return B_NOT_ALLOWED;
|
||||||
|
|
||||||
|
for (unsigned i = 0; i < fContext->nb_streams; i++) {
|
||||||
|
AVStream* stream = fContext->streams[i];
|
||||||
|
TRACE(" stream[%u] time_base: (%d/%d), codec->time_base: (%d/%d)\n",
|
||||||
|
i, stream->time_base.num, stream->time_base.den,
|
||||||
|
stream->codec->time_base.num, stream->codec->time_base.den);
|
||||||
|
}
|
||||||
|
|
||||||
int result = av_write_header(fContext);
|
int result = av_write_header(fContext);
|
||||||
if (result < 0)
|
if (result < 0)
|
||||||
TRACE(" av_write_header(): %d\n", result);
|
TRACE(" av_write_header(): %d\n", result);
|
||||||
else
|
else
|
||||||
fHeaderWritten = true;
|
fHeaderWritten = true;
|
||||||
|
|
||||||
|
TRACE(" wrote header\n");
|
||||||
|
for (unsigned i = 0; i < fContext->nb_streams; i++) {
|
||||||
|
AVStream* stream = fContext->streams[i];
|
||||||
|
TRACE(" stream[%u] time_base: (%d/%d), codec->time_base: (%d/%d)\n",
|
||||||
|
i, stream->time_base.num, stream->time_base.den,
|
||||||
|
stream->codec->time_base.num, stream->codec->time_base.den);
|
||||||
|
}
|
||||||
|
|
||||||
return result == 0 ? B_OK : B_ERROR;
|
return result == 0 ? B_OK : B_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,8 +483,8 @@ status_t
|
|||||||
AVFormatWriter::WriteChunk(void* _cookie, const void* chunkBuffer,
|
AVFormatWriter::WriteChunk(void* _cookie, const void* chunkBuffer,
|
||||||
size_t chunkSize, media_encode_info* encodeInfo)
|
size_t chunkSize, media_encode_info* encodeInfo)
|
||||||
{
|
{
|
||||||
TRACE("AVFormatWriter::WriteChunk(%p, %ld, %p)\n", chunkBuffer, chunkSize,
|
TRACE_PACKET("AVFormatWriter::WriteChunk(%p, %ld, %p)\n", chunkBuffer,
|
||||||
encodeInfo);
|
chunkSize, encodeInfo);
|
||||||
|
|
||||||
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
|
StreamCookie* cookie = reinterpret_cast<StreamCookie*>(_cookie);
|
||||||
return cookie->WriteChunk(chunkBuffer, chunkSize, encodeInfo);
|
return cookie->WriteChunk(chunkBuffer, chunkSize, encodeInfo);
|
||||||
|
|||||||
@@ -48,18 +48,18 @@ const EncoderDescription gEncoderTable[] = {
|
|||||||
B_MEDIA_RAW_VIDEO,
|
B_MEDIA_RAW_VIDEO,
|
||||||
B_MEDIA_ENCODED_VIDEO
|
B_MEDIA_ENCODED_VIDEO
|
||||||
},
|
},
|
||||||
// {
|
{
|
||||||
// {
|
{
|
||||||
// "MP3 Audio",
|
"Raw Audio",
|
||||||
// "mp3",
|
"pcm",
|
||||||
// 0,
|
0,
|
||||||
// CODEC_ID_MP3,
|
CODEC_ID_PCM_S16LE,
|
||||||
// { 0 }
|
{ 0 }
|
||||||
// },
|
},
|
||||||
// B_ANY_FORMAT_FAMILY,
|
B_ANY_FORMAT_FAMILY,
|
||||||
// B_MEDIA_RAW_AUDIO,
|
B_MEDIA_RAW_AUDIO,
|
||||||
// B_MEDIA_ENCODED_AUDIO
|
B_MEDIA_ENCODED_AUDIO
|
||||||
// }
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const size_t gEncoderCount = sizeof(gEncoderTable) / sizeof(EncoderDescription);
|
const size_t gEncoderCount = sizeof(gEncoderTable) / sizeof(EncoderDescription);
|
||||||
|
|||||||
Reference in New Issue
Block a user