summaryrefslogtreecommitdiff
path: root/chromium/media/base/android/media_source_player.h
blob: ef822d49b28306305b710f5d84149ce9d580e5b4 (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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
// Copyright (c) 2013 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.

#ifndef MEDIA_BASE_ANDROID_MEDIA_SOURCE_PLAYER_H_
#define MEDIA_BASE_ANDROID_MEDIA_SOURCE_PLAYER_H_

#include <jni.h>
#include <map>
#include <string>
#include <vector>

#include "base/android/scoped_java_ref.h"
#include "base/callback.h"
#include "base/cancelable_callback.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/weak_ptr.h"
#include "base/threading/thread.h"
#include "base/time/default_tick_clock.h"
#include "base/time/time.h"
#include "media/base/android/demuxer_android.h"
#include "media/base/android/media_codec_bridge.h"
#include "media/base/android/media_decoder_job.h"
#include "media/base/android/media_player_android.h"
#include "media/base/clock.h"
#include "media/base/media_export.h"

namespace media {

class AudioDecoderJob;
class AudioTimestampHelper;
class VideoDecoderJob;

// This class handles media source extensions on Android. It uses Android
// MediaCodec to decode audio and video streams in two separate threads.
class MEDIA_EXPORT MediaSourcePlayer : public MediaPlayerAndroid,
                                       public DemuxerAndroidClient {
 public:
  // Constructs a player with the given ID and demuxer. |manager| must outlive
  // the lifetime of this object.
  MediaSourcePlayer(int player_id,
                    MediaPlayerManager* manager,
                    scoped_ptr<DemuxerAndroid> demuxer);
  virtual ~MediaSourcePlayer();

  static bool IsTypeSupported(const std::vector<uint8>& scheme_uuid,
                              const std::string& security_level,
                              const std::string& container,
                              const std::vector<std::string>& codecs);

  // MediaPlayerAndroid implementation.
  virtual void SetVideoSurface(gfx::ScopedJavaSurface surface) OVERRIDE;
  virtual void Start() OVERRIDE;
  virtual void Pause(bool is_media_related_action ALLOW_UNUSED) OVERRIDE;
  virtual void SeekTo(const base::TimeDelta& timestamp) OVERRIDE;
  virtual void Release() OVERRIDE;
  virtual void SetVolume(double volume) OVERRIDE;
  virtual int GetVideoWidth() OVERRIDE;
  virtual int GetVideoHeight() OVERRIDE;
  virtual base::TimeDelta GetCurrentTime() OVERRIDE;
  virtual base::TimeDelta GetDuration() OVERRIDE;
  virtual bool IsPlaying() OVERRIDE;
  virtual bool CanPause() OVERRIDE;
  virtual bool CanSeekForward() OVERRIDE;
  virtual bool CanSeekBackward() OVERRIDE;
  virtual bool IsPlayerReady() OVERRIDE;
  virtual void SetDrmBridge(MediaDrmBridge* drm_bridge) OVERRIDE;
  virtual void OnKeyAdded() OVERRIDE;

  // DemuxerAndroidClient implementation.
  virtual void OnDemuxerConfigsAvailable(const DemuxerConfigs& params) OVERRIDE;
  virtual void OnDemuxerDataAvailable(const DemuxerData& params) OVERRIDE;
  virtual void OnDemuxerSeekDone(
      const base::TimeDelta& actual_browser_seek_time) OVERRIDE;
  virtual void OnDemuxerDurationChanged(base::TimeDelta duration) OVERRIDE;

 private:
  // Update the current timestamp.
  void UpdateTimestamps(const base::TimeDelta& presentation_timestamp,
                        size_t audio_output_bytes);

  // Helper function for starting media playback.
  void StartInternal();

  // Playback is completed for one channel.
  void PlaybackCompleted(bool is_audio);

  // Called when the decoder finishes its task.
  void MediaDecoderCallback(
        bool is_audio, MediaCodecStatus status,
        const base::TimeDelta& presentation_timestamp,
        size_t audio_output_bytes);

  // Gets MediaCrypto object from |drm_bridge_|.
  base::android::ScopedJavaLocalRef<jobject> GetMediaCrypto();

  // Callback to notify that MediaCrypto is ready in |drm_bridge_|.
  void OnMediaCryptoReady();

  // Handle pending events if all the decoder jobs are not currently decoding.
  void ProcessPendingEvents();

  // Helper method to clear any pending |SURFACE_CHANGE_EVENT_PENDING|
  // and reset |video_decoder_job_| to null.
  void ResetVideoDecoderJob();

  // Helper methods to configure the decoder jobs.
  void ConfigureVideoDecoderJob();
  void ConfigureAudioDecoderJob();

  // Flush the decoders and clean up all the data needs to be decoded.
  void ClearDecodingData();

  // Called to decode more data.
  void DecodeMoreAudio();
  void DecodeMoreVideo();

  // Functions check whether audio/video is present.
  bool HasVideo();
  bool HasAudio();

  // Functions that check whether audio/video stream has reached end of output
  // or are not present in player configuration.
  bool AudioFinished();
  bool VideoFinished();

  // Determine seekability based on duration.
  bool Seekable();

  // Called when the |decoder_starvation_callback_| times out.
  void OnDecoderStarved();

  // Starts the |decoder_starvation_callback_| task with the timeout value.
  // |presentation_timestamp| - The presentation timestamp used for starvation
  // timeout computations. It represents the timestamp of the last piece of
  // decoded data.
  void StartStarvationCallback(const base::TimeDelta& presentation_timestamp);

  // Schedules a seek event in |pending_events_| and calls StopDecode() on all
  // the MediaDecoderJobs. Sets clock to |seek_time|, and resets
  // |pending_seek_|. There must not already be a seek event in
  // |pending_events_|.
  void ScheduleSeekEventAndStopDecoding(const base::TimeDelta& seek_time);

  // Schedules a browser seek event. We must not currently be processing any
  // seek. Note that there is possibility that browser seek of renderer demuxer
  // may unexpectedly stall due to lack of buffered data at or after the browser
  // seek time.
  // TODO(wolenetz): Instead of doing hack browser seek, replay cached data
  // since last keyframe. See http://crbug.com/304234.
  void BrowserSeekToCurrentTime();

  // Helper function to set the volume.
  void SetVolumeInternal();

  // Helper function to determine whether a protected surface is needed for
  // video playback.
  bool IsProtectedSurfaceRequired();

  // Called when a MediaDecoderJob finishes prefetching data. Once all
  // MediaDecoderJobs have prefetched data, then this method updates
  // |start_time_ticks_| and |start_presentation_timestamp_| so that video can
  // resync with audio and starts decoding.
  void OnPrefetchDone();

  // Test-only method to setup hook for the completion of the next decode cycle.
  // This callback state is cleared when it is next run.
  // Prevent usage creep by only calling this from the
  // ReleaseWithOnPrefetchDoneAlreadyPosted MediaSourcePlayerTest.
  void set_decode_callback_for_testing(const base::Closure& test_decode_cb) {
    decode_callback_for_testing_ = test_decode_cb;
  }

  // TODO(qinmin/wolenetz): Reorder these based on their priority from
  // ProcessPendingEvents(). Release() and other routines are dependent upon
  // priority consistency.
  enum PendingEventFlags {
    NO_EVENT_PENDING = 0,
    SEEK_EVENT_PENDING = 1 << 0,
    SURFACE_CHANGE_EVENT_PENDING = 1 << 1,
    CONFIG_CHANGE_EVENT_PENDING = 1 << 2,
    PREFETCH_REQUEST_EVENT_PENDING = 1 << 3,
    PREFETCH_DONE_EVENT_PENDING = 1 << 4,
  };

  static const char* GetEventName(PendingEventFlags event);
  bool IsEventPending(PendingEventFlags event) const;
  void SetPendingEvent(PendingEventFlags event);
  void ClearPendingEvent(PendingEventFlags event);

  scoped_ptr<DemuxerAndroid> demuxer_;

  // Pending event that the player needs to do.
  unsigned pending_event_;

  // Stats about the media.
  base::TimeDelta duration_;
  int width_;
  int height_;
  AudioCodec audio_codec_;
  VideoCodec video_codec_;
  int num_channels_;
  int sampling_rate_;
  // TODO(xhwang/qinmin): Add |video_extra_data_|.
  std::vector<uint8> audio_extra_data_;
  bool reached_audio_eos_;
  bool reached_video_eos_;
  bool playing_;
  bool is_audio_encrypted_;
  bool is_video_encrypted_;
  double volume_;

  // base::TickClock used by |clock_|.
  base::DefaultTickClock default_tick_clock_;

  // Reference clock. Keeps track of current playback time.
  Clock clock_;

  // Timestamps for providing simple A/V sync. When start decoding an audio
  // chunk, we record its presentation timestamp and the current system time.
  // Then we use this information to estimate when the next audio/video frame
  // should be rendered.
  // TODO(qinmin): Need to fix the problem if audio/video lagged too far behind
  // due to network or decoding problem.
  base::TimeTicks start_time_ticks_;
  base::TimeDelta start_presentation_timestamp_;

  // The surface object currently owned by the player.
  gfx::ScopedJavaSurface surface_;

  // Track whether or not the player has received any video data since the most
  // recent of player construction, end of last seek, or receiving and
  // detecting a |kConfigChanged| access unit from the demuxer.
  // If no such video data has been received, the next video data begins with
  // an I-frame. Otherwise, we have no such guarantee.
  bool next_video_data_is_iframe_;

  // Flag that is true if doing a hack browser seek or false if doing a
  // regular seek. Only valid when |SEEK_EVENT_PENDING| is pending.
  // TODO(wolenetz): Instead of doing hack browser seek, replay cached data
  // since last keyframe. See http://crbug.com/304234.
  bool doing_browser_seek_;

  // If already doing a browser seek when a regular seek request arrives,
  // these fields remember the regular seek so OnDemuxerSeekDone() can trigger
  // it when the browser seek is done. These are only valid when
  // |SEEK_EVENT_PENDING| is pending.
  bool pending_seek_;
  base::TimeDelta pending_seek_time_;

  // Decoder jobs.
  scoped_ptr<AudioDecoderJob, MediaDecoderJob::Deleter> audio_decoder_job_;
  scoped_ptr<VideoDecoderJob, MediaDecoderJob::Deleter> video_decoder_job_;

  bool reconfig_audio_decoder_;
  bool reconfig_video_decoder_;

  // Track the most recent preroll target. Decoder re-creation needs this to
  // resume any in-progress preroll.
  base::TimeDelta preroll_timestamp_;

  // A cancelable task that is posted when the audio decoder starts requesting
  // new data. This callback runs if no data arrives before the timeout period
  // elapses.
  base::CancelableClosure decoder_starvation_callback_;

  // Object to calculate the current audio timestamp for A/V sync.
  scoped_ptr<AudioTimestampHelper> audio_timestamp_helper_;

  // Weak pointer passed to media decoder jobs for callbacks.
  base::WeakPtrFactory<MediaSourcePlayer> weak_this_;

  MediaDrmBridge* drm_bridge_;

  // No decryption key available to decrypt the encrypted buffer. In this case,
  // the player should pause. When a new key is added (OnKeyAdded()), we should
  // try to start playback again.
  bool is_waiting_for_key_;

  // Test-only callback for hooking the completion of the next decode cycle.
  base::Closure decode_callback_for_testing_;

  friend class MediaSourcePlayerTest;
  DISALLOW_COPY_AND_ASSIGN(MediaSourcePlayer);
};

}  // namespace media

#endif  // MEDIA_BASE_ANDROID_MEDIA_SOURCE_PLAYER_H_