* Do no manually allocate the buffer for the
ByteIOContext. libavformat may reallocate it on demand, we need to use the matching allocation methods. * Init the ByteIOContext with the proper "write flag". This solves a busy loop when writing the trailer of MKV files, since the first buffer was initially skipped and the MKV muxer can not seek back in the stream where it wants. * Get rid of the fCalculatePTS member, and calculate PTS of audio packets as well. I don't remember why I prevented that, however VLC complains about audio packets having wrong PTS (with or without this change) Our own MediaPlayer plays videos generated by (a modified) Clockwerk at least once, but seeking subsequently fails. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@38851 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -75,7 +75,6 @@ private:
|
||||
AVFormatContext* fContext;
|
||||
AVStream* fStream;
|
||||
AVPacket fPacket;
|
||||
bool fCalculatePTS;
|
||||
// Since different threads may write to the target,
|
||||
// we need to protect the file position and I/O by a lock.
|
||||
BLocker* fStreamLock;
|
||||
@@ -88,7 +87,6 @@ AVFormatWriter::StreamCookie::StreamCookie(AVFormatContext* context,
|
||||
:
|
||||
fContext(context),
|
||||
fStream(NULL),
|
||||
fCalculatePTS(false),
|
||||
fStreamLock(streamLock)
|
||||
{
|
||||
av_init_packet(&fPacket);
|
||||
@@ -160,8 +158,6 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
||||
// Some formats want stream headers to be separate
|
||||
if ((fContext->oformat->flags & AVFMT_GLOBALHEADER) != 0)
|
||||
fStream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
|
||||
|
||||
fCalculatePTS = true;
|
||||
} else if (format->type == B_MEDIA_RAW_AUDIO) {
|
||||
fStream->codec->codec_type = CODEC_TYPE_AUDIO;
|
||||
#if GET_CONTEXT_DEFAULTS
|
||||
@@ -170,11 +166,6 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
||||
#endif
|
||||
// frame rate
|
||||
fStream->codec->sample_rate = (int)format->u.raw_audio.frame_rate;
|
||||
// NOTE: API example does not do this:
|
||||
// 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;
|
||||
|
||||
// channels
|
||||
fStream->codec->channels = format->u.raw_audio.channel_count;
|
||||
@@ -233,8 +224,6 @@ AVFormatWriter::StreamCookie::Init(const media_format* format,
|
||||
// The bits match 1:1 for media_multi_channels and FFmpeg defines.
|
||||
fStream->codec->channel_layout = format->u.raw_audio.channel_mask;
|
||||
}
|
||||
|
||||
fCalculatePTS = false;
|
||||
}
|
||||
|
||||
TRACE(" stream->time_base: (%d/%d), codec->time_base: (%d/%d))\n",
|
||||
@@ -249,8 +238,9 @@ status_t
|
||||
AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
|
||||
size_t chunkSize, media_encode_info* encodeInfo)
|
||||
{
|
||||
TRACE_PACKET("AVFormatWriter::StreamCookie::WriteChunk(%p, %ld, "
|
||||
"start_time: %lld)\n", chunkBuffer, chunkSize, encodeInfo->start_time);
|
||||
TRACE_PACKET("AVFormatWriter::StreamCookie[%d]::WriteChunk(%p, %ld, "
|
||||
"start_time: %lld)\n", fStream->index, chunkBuffer, chunkSize,
|
||||
encodeInfo->start_time);
|
||||
|
||||
BAutolock _(fStreamLock);
|
||||
|
||||
@@ -260,14 +250,13 @@ AVFormatWriter::StreamCookie::WriteChunk(const void* chunkBuffer,
|
||||
fPacket.data = const_cast<uint8_t*>((const uint8_t*)chunkBuffer);
|
||||
fPacket.size = chunkSize;
|
||||
|
||||
if (fCalculatePTS) {
|
||||
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);
|
||||
}
|
||||
fPacket.pts = int64_t((double)encodeInfo->start_time
|
||||
* fStream->time_base.den / (1000000.0 * fStream->time_base.num)
|
||||
+ 0.5);
|
||||
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():
|
||||
// TODO:
|
||||
@@ -315,7 +304,6 @@ AVFormatWriter::AVFormatWriter()
|
||||
:
|
||||
fContext(avformat_alloc_context()),
|
||||
fHeaderWritten(false),
|
||||
fIOBuffer(NULL),
|
||||
fStreamLock("stream lock")
|
||||
{
|
||||
TRACE("AVFormatWriter::AVFormatWriter\n");
|
||||
@@ -339,8 +327,7 @@ AVFormatWriter::~AVFormatWriter()
|
||||
}
|
||||
|
||||
av_free(fContext);
|
||||
|
||||
delete[] fIOBuffer;
|
||||
av_free(fIOContext.buffer);
|
||||
}
|
||||
|
||||
|
||||
@@ -352,14 +339,13 @@ AVFormatWriter::Init(const media_file_format* fileFormat)
|
||||
{
|
||||
TRACE("AVFormatWriter::Init()\n");
|
||||
|
||||
delete[] fIOBuffer;
|
||||
fIOBuffer = new(std::nothrow) uint8[kIOBufferSize];
|
||||
if (fIOBuffer == NULL)
|
||||
uint8* buffer = static_cast<uint8*>(av_malloc(kIOBufferSize));
|
||||
if (buffer == NULL)
|
||||
return B_NO_MEMORY;
|
||||
|
||||
// Init I/O context with buffer and hook functions, pass ourself as
|
||||
// cookie.
|
||||
if (init_put_byte(&fIOContext, fIOBuffer, kIOBufferSize, 0, this,
|
||||
if (init_put_byte(&fIOContext, buffer, kIOBufferSize, 1, this,
|
||||
0, _Write, _Seek) != 0) {
|
||||
TRACE(" init_put_byte() failed!\n");
|
||||
return B_ERROR;
|
||||
@@ -369,7 +355,7 @@ AVFormatWriter::Init(const media_file_format* fileFormat)
|
||||
fContext->pb = &fIOContext;
|
||||
|
||||
// Set the AVOutputFormat according to fileFormat...
|
||||
fContext->oformat = guess_format(fileFormat->short_name,
|
||||
fContext->oformat = av_guess_format(fileFormat->short_name,
|
||||
fileFormat->file_extension, fileFormat->mime_type);
|
||||
if (fContext->oformat == NULL) {
|
||||
TRACE(" failed to find AVOuputFormat for %s\n",
|
||||
@@ -430,10 +416,11 @@ AVFormatWriter::CommitHeader()
|
||||
int result = av_write_header(fContext);
|
||||
if (result < 0)
|
||||
TRACE(" av_write_header(): %d\n", result);
|
||||
else
|
||||
fHeaderWritten = true;
|
||||
|
||||
#if TRACE_AVFORMAT_WRITER
|
||||
// We need to close the codecs we opened, even in case of failure.
|
||||
fHeaderWritten = true;
|
||||
|
||||
#ifdef TRACE_AVFORMAT_WRITER
|
||||
TRACE(" wrote header\n");
|
||||
for (unsigned i = 0; i < fContext->nb_streams; i++) {
|
||||
AVStream* stream = fContext->streams[i];
|
||||
|
||||
@@ -46,17 +46,15 @@ public:
|
||||
private:
|
||||
static int _Write(void* cookie, uint8* buffer,
|
||||
int bufferSize);
|
||||
|
||||
static off_t _Seek(void* cookie, off_t offset, int whence);
|
||||
|
||||
private:
|
||||
class StreamCookie;
|
||||
class StreamCookie;
|
||||
|
||||
AVFormatContext* fContext;
|
||||
bool fHeaderWritten;
|
||||
|
||||
ByteIOContext fIOContext;
|
||||
uint8* fIOBuffer;
|
||||
|
||||
StreamCookie** fStreams;
|
||||
BLocker fStreamLock;
|
||||
|
||||
Reference in New Issue
Block a user