blob: fc597091d4b2c13c6a7dce28bc11103c6fd1ee90 [file] [log] [blame]
// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/ffmpeg/ffmpeg_common.h"
#include "base/logging.h"
namespace media {
static const AVRational kMicrosBase = { 1, base::Time::kMicrosecondsPerSecond };
base::TimeDelta ConvertFromTimeBase(const AVRational& time_base,
int64 timestamp) {
int64 microseconds = av_rescale_q(timestamp, time_base, kMicrosBase);
return base::TimeDelta::FromMicroseconds(microseconds);
}
int64 ConvertToTimeBase(const AVRational& time_base,
const base::TimeDelta& timestamp) {
return av_rescale_q(timestamp.InMicroseconds(), kMicrosBase, time_base);
}
VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
switch (codec_id) {
case CODEC_ID_VC1:
return kCodecVC1;
case CODEC_ID_H264:
return kCodecH264;
case CODEC_ID_THEORA:
return kCodecTheora;
case CODEC_ID_MPEG2VIDEO:
return kCodecMPEG2;
case CODEC_ID_MPEG4:
return kCodecMPEG4;
case CODEC_ID_VP8:
return kCodecVP8;
default:
NOTREACHED();
}
return kUnknown;
}
CodecID VideoCodecToCodecID(VideoCodec video_codec) {
switch (video_codec) {
case kCodecVC1:
return CODEC_ID_VC1;
case kCodecH264:
return CODEC_ID_H264;
case kCodecTheora:
return CODEC_ID_THEORA;
case kCodecMPEG2:
return CODEC_ID_MPEG2VIDEO;
case kCodecMPEG4:
return CODEC_ID_MPEG4;
case kCodecVP8:
return CODEC_ID_VP8;
default:
NOTREACHED();
}
return CODEC_ID_NONE;
}
bool GetSeekTimeAfter(AVStream* stream, const base::TimeDelta& timestamp,
base::TimeDelta* seek_time) {
DCHECK(stream);
DCHECK(timestamp >= base::TimeDelta::FromSeconds(0));
DCHECK(seek_time);
// Make sure we have index data.
if (!stream->index_entries || stream->nb_index_entries <= 0)
return false;
// Search for the index entry >= the specified timestamp.
int64 stream_ts = ConvertToTimeBase(stream->time_base, timestamp);
int i = av_index_search_timestamp(stream, stream_ts, 0);
if (i < 0)
return false;
if (stream->index_entries[i].timestamp == static_cast<int64>(AV_NOPTS_VALUE))
return false;
*seek_time = ConvertFromTimeBase(stream->time_base,
stream->index_entries[i].timestamp);
return true;
}
bool GetStreamByteCountOverRange(AVStream* stream,
const base::TimeDelta& start_time,
const base::TimeDelta& end_time,
int64* bytes,
base::TimeDelta* range_start,
base::TimeDelta* range_end) {
DCHECK(stream);
DCHECK(start_time < end_time);
DCHECK(start_time >= base::TimeDelta::FromSeconds(0));
DCHECK(bytes);
DCHECK(range_start);
DCHECK(range_end);
// Make sure the stream has index data.
if (!stream->index_entries || stream->nb_index_entries <= 1)
return false;
// Search for the index entries associated with the timestamps.
int64 start_ts = ConvertToTimeBase(stream->time_base, start_time);
int64 end_ts = ConvertToTimeBase(stream->time_base, end_time);
int i = av_index_search_timestamp(stream, start_ts, AVSEEK_FLAG_BACKWARD);
int j = av_index_search_timestamp(stream, end_ts, 0);
// Make sure start & end indexes are valid.
if (i < 0 || j < 0)
return false;
// Shouldn't happen because start & end use different seek flags, but we want
// to know about it if they end up pointing to the same index entry.
DCHECK_NE(i, j);
AVIndexEntry* start_ie = &stream->index_entries[i];
AVIndexEntry* end_ie = &stream->index_entries[j];
// Make sure index entries have valid timestamps & position data.
if (start_ie->timestamp == static_cast<int64>(AV_NOPTS_VALUE) ||
end_ie->timestamp == static_cast<int64>(AV_NOPTS_VALUE) ||
start_ie->timestamp >= end_ie->timestamp ||
start_ie->pos >= end_ie->pos) {
return false;
}
*bytes = end_ie->pos - start_ie->pos;
*range_start = ConvertFromTimeBase(stream->time_base, start_ie->timestamp);
*range_end = ConvertFromTimeBase(stream->time_base, end_ie->timestamp);
return true;
}
} // namespace media