* Copyright (c) 2007, Marcus Overhagen
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
* IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <SupportDefs.h>
#include <stdio.h>
#include "ReaderPlugin.h"
#include "Index.h"
#ifdef TRACE_INDEX
#define TRACE printf
#else
#define TRACE(a...)
#endif
#define ERROR(a...) fprintf(stderr, a)
Index::Index(BPositionIO *source, OpenDMLParser *parser)
: fSource(source)
, fParser(parser)
{
fStreamCount = parser->StreamCount();
fStreamData.resize(fStreamCount);
}
Index::~Index()
{
fStreamData.clear();
}
status_t
Index::GetNextChunkInfo(int stream_index, off_t *start,
uint32 *size, bool *keyframe) {
MediaStream *data = &fStreamData[stream_index];
if (data->current_chunk < data->seek_index_next) {
*keyframe = data->seek_index[data->current_chunk].keyframe;
*start = data->seek_index[data->current_chunk].position + 8;
*size = data->seek_index[data->current_chunk].size;
data->current_chunk++;
return B_OK;
}
data->current_chunk = 0;
return B_LAST_BUFFER_ERROR;
}
status_t
Index::Seek(int stream_index, uint32 seekTo, int64 *frame,
bigtime_t *time, bool readOnly) {
TRACE("Index::Seek: stream %d, seekTo%s%s%s%s, time %Ld, "
"frame %Ld\n", stream_index,
(seekTo & B_MEDIA_SEEK_TO_TIME) ? " B_MEDIA_SEEK_TO_TIME" : "",
(seekTo & B_MEDIA_SEEK_TO_FRAME) ? " B_MEDIA_SEEK_TO_FRAME" : "",
(seekTo & B_MEDIA_SEEK_CLOSEST_FORWARD) ?
" B_MEDIA_SEEK_CLOSEST_FORWARD" : "",
(seekTo & B_MEDIA_SEEK_CLOSEST_BACKWARD) ?
" B_MEDIA_SEEK_CLOSEST_BACKWARD" : "",
*time, *frame);
const OpenDMLStream *stream = fParser->StreamInfo(stream_index);
MediaStream *data = &fStreamData[stream_index];
int64 frame_pos;
if (seekTo & B_MEDIA_SEEK_TO_FRAME)
frame_pos = *frame;
else if (seekTo & B_MEDIA_SEEK_TO_TIME) {
frame_pos = (*time * stream->frames_per_sec_rate)
/ (1000000LL * stream->frames_per_sec_scale);
} else
return B_BAD_VALUE;
if (stream->is_audio) {
for (uint32 i = 1; i < data->seek_index_next; i++) {
if (data->seek_index[i].frame_no > frame_pos) {
frame_pos = data->seek_index[i-1].frame_no;
if (!readOnly) {
data->current_chunk = i-1;
}
goto done;
}
if (i+1 == data->seek_index_next) {
frame_pos = data->seek_index[i].frame_no;
if (!readOnly) {
data->current_chunk = i;
}
goto done;
}
}
} else if (stream->is_video) {
int64 pos = 0;
int64 lastKeyframePos = 0;
int64 lastKeyframeIndex = 0;
for (uint32 i = 0; i < data->seek_index_next; i++) {
if (data->seek_index[i].keyframe) {
lastKeyframePos = pos;
lastKeyframeIndex = i;
TRACE("keyframe at index %ld, frame %Ld (seek: %Ld)\n", i,
pos, frame_pos);
}
if (seekTo & B_MEDIA_SEEK_CLOSEST_BACKWARD) {
if (pos == frame_pos) {
frame_pos = lastKeyframePos;
if (!readOnly)
data->current_chunk = lastKeyframeIndex;
goto done;
}
} else if (seekTo & B_MEDIA_SEEK_CLOSEST_FORWARD) {
if (pos >= frame_pos && pos == lastKeyframePos) {
frame_pos = lastKeyframePos;
if (!readOnly)
data->current_chunk = lastKeyframeIndex;
goto done;
}
} else {
if (pos == frame_pos) {
if (!readOnly)
data->current_chunk = i;
goto done;
}
}
pos++;
}
} else {
return B_BAD_VALUE;
}
ERROR("libOpenDML: seek failed, position not found\n");
return B_ERROR;
done:
TRACE("seek done: index: pos %Ld\n", data->current_chunk);
*frame = frame_pos;
*time = (frame_pos * 1000000LL * stream->frames_per_sec_scale)
/ stream->frames_per_sec_rate;
return B_OK;
}
void
Index::AddIndex(int stream_index, off_t position, uint32 size, uint64 frame, bigtime_t pts, bool keyframe) {
IndexEntry seek_index;
seek_index.frame_no = frame;
seek_index.position = position;
seek_index.size = size;
seek_index.pts = pts;
seek_index.keyframe = keyframe;
fStreamData[stream_index].seek_index.push_back(seek_index);
fStreamData[stream_index].seek_index_next++;
}
void
Index::DumpIndex(int stream_index)
{
IndexEntry _index;
for (uint32 i = 0; i < fStreamData[stream_index].seek_index_next; i++) {
_index = fStreamData[stream_index].seek_index[i];
printf("index %ld Frame %Ld, pos %Ld, size %ld, pts %Ld\n",i,_index.frame_no, _index.position, _index.size, _index.pts);
}
}