2014-07-14 21:35:57 +00:00
|
|
|
// Copyright 2014 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.
|
|
|
|
// Media parser for a Widevine Media Format (WVM) file.
|
|
|
|
|
|
|
|
#ifndef MEDIA_FORMATS_WVM_WVM_MEDIA_PARSER_H_
|
|
|
|
#define MEDIA_FORMATS_WVM_WVM_MEDIA_PARSER_H_
|
|
|
|
|
|
|
|
#include <deque>
|
2014-09-15 20:11:37 +00:00
|
|
|
#include <map>
|
2014-07-14 21:35:57 +00:00
|
|
|
#include <string>
|
|
|
|
#include <vector>
|
2014-10-01 19:35:23 +00:00
|
|
|
|
2016-01-21 18:30:29 +00:00
|
|
|
#include "packager/base/compiler_specific.h"
|
2014-10-01 22:10:21 +00:00
|
|
|
#include "packager/base/memory/scoped_ptr.h"
|
|
|
|
#include "packager/media/base/media_parser.h"
|
|
|
|
#include "packager/media/base/network_util.h"
|
|
|
|
#include "packager/media/filters/h264_byte_to_unit_stream_converter.h"
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2016-05-20 21:19:33 +00:00
|
|
|
namespace shaka {
|
2014-07-14 21:35:57 +00:00
|
|
|
namespace media {
|
2014-09-30 16:58:43 +00:00
|
|
|
|
2016-03-25 18:02:43 +00:00
|
|
|
class AesCbcDecryptor;
|
2014-10-09 19:56:51 +00:00
|
|
|
class KeySource;
|
2014-09-30 16:58:43 +00:00
|
|
|
struct EncryptionKey;
|
|
|
|
|
2014-07-14 21:35:57 +00:00
|
|
|
namespace wvm {
|
|
|
|
|
|
|
|
struct DemuxStreamIdMediaSample {
|
2014-09-16 19:55:49 +00:00
|
|
|
public:
|
|
|
|
DemuxStreamIdMediaSample();
|
|
|
|
~DemuxStreamIdMediaSample();
|
2014-09-30 21:52:21 +00:00
|
|
|
uint32_t demux_stream_id;
|
|
|
|
uint32_t parsed_audio_or_video_stream_id;
|
2014-07-14 21:35:57 +00:00
|
|
|
scoped_refptr<MediaSample> media_sample;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct PrevSampleData {
|
|
|
|
public:
|
2014-09-16 19:55:49 +00:00
|
|
|
PrevSampleData();
|
|
|
|
~PrevSampleData();
|
|
|
|
void Reset();
|
2014-07-14 21:35:57 +00:00
|
|
|
scoped_refptr<MediaSample> audio_sample;
|
|
|
|
scoped_refptr<MediaSample> video_sample;
|
2014-09-30 21:52:21 +00:00
|
|
|
uint32_t audio_stream_id;
|
|
|
|
uint32_t video_stream_id;
|
|
|
|
int64_t audio_sample_duration;
|
|
|
|
int64_t video_sample_duration;
|
2014-07-14 21:35:57 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class WvmMediaParser : public MediaParser {
|
|
|
|
public:
|
|
|
|
WvmMediaParser();
|
2015-07-22 23:40:45 +00:00
|
|
|
~WvmMediaParser() override;
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2016-01-21 18:30:29 +00:00
|
|
|
/// @name MediaParser implementation overrides.
|
|
|
|
/// @{
|
2015-07-22 23:40:45 +00:00
|
|
|
void Init(const InitCB& init_cb,
|
|
|
|
const NewSampleCB& new_sample_cb,
|
|
|
|
KeySource* decryption_key_source) override;
|
2016-01-21 18:30:29 +00:00
|
|
|
bool Flush() override WARN_UNUSED_RESULT;
|
|
|
|
bool Parse(const uint8_t* buf, int size) override WARN_UNUSED_RESULT;
|
|
|
|
/// @}
|
2014-07-14 21:35:57 +00:00
|
|
|
|
|
|
|
private:
|
|
|
|
enum Tag {
|
|
|
|
CypherVersion = 0,
|
|
|
|
TrackOffset = 1,
|
|
|
|
TrackSize = 2,
|
|
|
|
TrackDuration = 3,
|
|
|
|
TrackBitRate = 4,
|
|
|
|
TrackTrickPlayRate = 5,
|
|
|
|
TrackAdaptationInterval = 6,
|
|
|
|
TrackFlags = 7,
|
|
|
|
VideoType = 8,
|
|
|
|
VideoProfile = 9,
|
|
|
|
VideoLevel = 10,
|
|
|
|
VideoWidth = 11,
|
|
|
|
VideoHeight = 12,
|
|
|
|
VideoTicksPerFrame = 13,
|
|
|
|
VideoBitRate = 14,
|
|
|
|
AudioType = 15,
|
|
|
|
AudioProfile = 16,
|
|
|
|
AudioNumChannels = 17,
|
|
|
|
AudioSampleFrequency = 18,
|
|
|
|
AudioBitRate = 19,
|
|
|
|
TrackVersion = 20,
|
|
|
|
Title = 21,
|
|
|
|
Copyright = 22,
|
|
|
|
ChapterIndex = 23,
|
|
|
|
TimeIndex = 24,
|
|
|
|
Thumbnail = 25,
|
|
|
|
ObjectSeqNum = 26,
|
|
|
|
ThumbnailOffset = 27,
|
|
|
|
ThumbnailSize = 28,
|
|
|
|
NumEntries = 29,
|
|
|
|
Chapters = 30,
|
|
|
|
VideoPixelWidth = 31,
|
|
|
|
VideoPixelHeight = 32,
|
|
|
|
FileSize = 33,
|
|
|
|
SparseDownloadUrl = 34,
|
|
|
|
SparseDownloadRangeTranslations = 35,
|
|
|
|
SparseDownloadMap = 36,
|
|
|
|
AudioSampleSize = 37,
|
|
|
|
Audio_EsDescriptor = 38,
|
|
|
|
AVCDecoderConfigurationRecord = 39,
|
|
|
|
Audio_EC3SpecificData = 40,
|
|
|
|
AudioIdentifier = 41,
|
|
|
|
VideoStreamId = 42,
|
|
|
|
VideoStreamType = 43,
|
|
|
|
AudioStreamId = 44,
|
|
|
|
AudioStreamType = 45,
|
|
|
|
Audio_DtsSpecificData = 46,
|
|
|
|
Audio_AC3SpecificData = 47,
|
|
|
|
Unset = 48
|
|
|
|
};
|
|
|
|
|
|
|
|
enum State {
|
|
|
|
StartCode1 = 0,
|
|
|
|
StartCode2,
|
|
|
|
StartCode3,
|
|
|
|
StartCode4,
|
|
|
|
PackHeader1,
|
|
|
|
PackHeader2,
|
|
|
|
PackHeader3,
|
|
|
|
PackHeader4,
|
|
|
|
PackHeader5,
|
|
|
|
PackHeader6,
|
|
|
|
PackHeader7,
|
|
|
|
PackHeader8,
|
|
|
|
PackHeader9,
|
|
|
|
PackHeader10,
|
|
|
|
PackHeaderStuffingSkip,
|
|
|
|
SystemHeader1,
|
|
|
|
SystemHeader2,
|
|
|
|
SystemHeaderSkip,
|
|
|
|
PesStreamId,
|
|
|
|
PesPacketLength1,
|
|
|
|
PesPacketLength2,
|
|
|
|
PesExtension1,
|
|
|
|
PesExtension2,
|
|
|
|
PesExtension3,
|
|
|
|
Pts1,
|
|
|
|
Pts2,
|
|
|
|
Pts3,
|
|
|
|
Pts4,
|
|
|
|
Pts5,
|
|
|
|
Dts1,
|
|
|
|
Dts2,
|
|
|
|
Dts3,
|
|
|
|
Dts4,
|
|
|
|
Dts5,
|
|
|
|
PesHeaderData,
|
|
|
|
PesPayload,
|
|
|
|
EsPayload,
|
|
|
|
PsmPayload,
|
|
|
|
EcmPayload,
|
|
|
|
IndexPayload,
|
|
|
|
Padding,
|
|
|
|
ProgramEnd
|
|
|
|
};
|
|
|
|
|
2014-09-30 16:58:43 +00:00
|
|
|
bool ProcessEcm();
|
2014-07-14 21:35:57 +00:00
|
|
|
|
|
|
|
// Index denotes 'search index' in the WVM content.
|
|
|
|
bool ParseIndexEntry();
|
|
|
|
|
2015-01-12 21:17:10 +00:00
|
|
|
bool DemuxNextPes(bool is_program_end);
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2015-01-12 21:17:10 +00:00
|
|
|
void StartMediaSampleDemux();
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
template <typename T>
|
|
|
|
Tag GetTag(const uint8_t& tag,
|
|
|
|
const uint32_t& length,
|
|
|
|
const uint8_t* start_index,
|
|
|
|
T* value) {
|
|
|
|
if (length == sizeof(uint8_t)) {
|
|
|
|
*value = (uint8_t)(*start_index);
|
|
|
|
} else if (length == sizeof(int8_t)) {
|
|
|
|
*value = (int8_t)(*start_index);
|
|
|
|
} else if (length == sizeof(uint16_t)) {
|
|
|
|
*value = (uint16_t)(ntohsFromBuffer(start_index));
|
|
|
|
} else if (length == sizeof(int16_t)) {
|
|
|
|
*value = (int16_t)(ntohsFromBuffer(start_index));
|
|
|
|
} else if (length == sizeof(uint32_t)) {
|
|
|
|
*value = (uint32_t)(ntohlFromBuffer(start_index));
|
|
|
|
} else if (length == sizeof(int32_t)) {
|
|
|
|
*value = (int32_t)(ntohlFromBuffer(start_index));
|
|
|
|
} else if (length == sizeof(uint64_t)) {
|
|
|
|
*value = (uint64_t)(ntohllFromBuffer(start_index));
|
|
|
|
} else if (length == sizeof(int64_t)) {
|
|
|
|
*value = (int64_t)(ntohllFromBuffer(start_index));
|
2014-07-14 21:35:57 +00:00
|
|
|
} else {
|
|
|
|
*value = 0;
|
|
|
|
}
|
|
|
|
return Tag(tag);
|
|
|
|
}
|
|
|
|
|
2015-01-12 21:17:10 +00:00
|
|
|
// |must_process_encrypted| setting determines if Output() should attempt
|
|
|
|
// to ouput media sample as encrypted.
|
|
|
|
bool Output(bool must_process_encrypted);
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2014-09-30 16:58:43 +00:00
|
|
|
bool GetAssetKey(const uint32_t asset_id, EncryptionKey* encryption_key);
|
|
|
|
|
2014-07-14 21:35:57 +00:00
|
|
|
// Callback invoked by the ES media parser
|
|
|
|
// to emit a new audio/video access unit.
|
2014-10-15 21:56:12 +00:00
|
|
|
bool EmitSample(uint32_t parsed_audio_or_video_stream_id,
|
2014-09-30 21:52:21 +00:00
|
|
|
uint32_t stream_id,
|
|
|
|
scoped_refptr<MediaSample>& new_sample,
|
|
|
|
bool isLastSample);
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2014-10-15 21:56:12 +00:00
|
|
|
bool EmitPendingSamples();
|
2014-07-14 21:35:57 +00:00
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
bool EmitLastSample(uint32_t stream_id,
|
|
|
|
scoped_refptr<MediaSample>& new_sample);
|
2014-07-14 21:35:57 +00:00
|
|
|
|
|
|
|
// List of callbacks.t
|
|
|
|
InitCB init_cb_;
|
|
|
|
NewSampleCB new_sample_cb_;
|
|
|
|
|
|
|
|
// Whether |init_cb_| has been invoked.
|
|
|
|
bool is_initialized_;
|
|
|
|
// Internal content parsing state.
|
|
|
|
State parse_state_;
|
|
|
|
|
|
|
|
bool is_psm_needed_;
|
2014-09-30 21:52:21 +00:00
|
|
|
uint32_t skip_bytes_;
|
2014-07-14 21:35:57 +00:00
|
|
|
bool metadata_is_complete_;
|
2014-09-30 21:52:21 +00:00
|
|
|
uint8_t current_program_id_;
|
|
|
|
uint32_t pes_stream_id_;
|
|
|
|
uint32_t prev_pes_stream_id_;
|
|
|
|
uint16_t pes_packet_bytes_;
|
|
|
|
uint8_t pes_flags_1_;
|
|
|
|
uint8_t pes_flags_2_;
|
2014-09-30 16:58:43 +00:00
|
|
|
uint8_t prev_pes_flags_1_;
|
2014-09-30 21:52:21 +00:00
|
|
|
uint8_t pes_header_data_bytes_;
|
|
|
|
uint64_t timestamp_;
|
|
|
|
uint64_t pts_;
|
|
|
|
uint64_t dts_;
|
|
|
|
uint8_t index_program_id_;
|
2014-07-14 21:35:57 +00:00
|
|
|
scoped_refptr<MediaSample> media_sample_;
|
2014-11-25 21:42:16 +00:00
|
|
|
uint32_t crypto_unit_start_pos_;
|
2014-07-14 21:35:57 +00:00
|
|
|
PrevSampleData prev_media_sample_data_;
|
|
|
|
H264ByteToUnitStreamConverter byte_to_unit_stream_converter_;
|
|
|
|
|
2014-09-30 21:52:21 +00:00
|
|
|
std::vector<uint8_t, std::allocator<uint8_t> > ecm_;
|
|
|
|
std::vector<uint8_t> psm_data_;
|
|
|
|
std::vector<uint8_t> index_data_;
|
|
|
|
std::map<std::string, uint32_t> program_demux_stream_map_;
|
2014-07-14 21:35:57 +00:00
|
|
|
int stream_id_count_;
|
|
|
|
std::vector<scoped_refptr<StreamInfo> > stream_infos_;
|
|
|
|
std::deque<DemuxStreamIdMediaSample> media_sample_queue_;
|
2014-09-30 21:52:21 +00:00
|
|
|
std::vector<uint8_t> sample_data_;
|
2014-10-09 19:56:51 +00:00
|
|
|
KeySource* decryption_key_source_;
|
2016-03-25 18:02:43 +00:00
|
|
|
scoped_ptr<AesCbcDecryptor> content_decryptor_;
|
2014-07-14 21:35:57 +00:00
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(WvmMediaParser);
|
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace wvm
|
|
|
|
} // namespace media
|
2016-05-20 21:19:33 +00:00
|
|
|
} // namespace shaka
|
2014-07-14 21:35:57 +00:00
|
|
|
|
|
|
|
#endif // MEDIA_FORMATS_WVM_WVM_MEDIA_PARSER_H_
|