summaryrefslogtreecommitdiffstats
path: root/media/ffmpeg/ffmpeg_common.cc
blob: 9f5eaeb05a5be1d063aaa2992b2065f017d2189b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 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;
}

base::TimeDelta GetFrameDuration(AVStream* stream) {
  AVRational time_base = { stream->r_frame_rate.den, stream->r_frame_rate.num };
  return ConvertFromTimeBase(time_base, 1);
}

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