1.介紹:
MediaExtractor是Android中音視頻解復(fù)用器甫煞,可以將video和audio分離出來罕拂。android kitkat版本上支持本地和http的音視頻解復(fù)用溃卡,打算按照這個設(shè)計模式擴展電信IPTV的RTSP的音視頻解復(fù)用。
2.干貨:
MediaExtractor的入口是NuMediaExtractor,通過下面代碼即可實例化MediaExtractor:
sp<NuMediaExtractor> extractor = new NuMediaExtractor;
if (extractor->setDataSource(path) != OK) {
fprintf(stderr, "unable to instantiate extractor.\n");
extractor = NULL;
return 1;
}
for (size_t i = 0; i < extractor->countTracks(); ++i) {
sp<AMessage> decode_format;
status_t err = extractor->getTrackFormat(i, &decode_format);
CHECK_EQ(err, (status_t)OK);
AString mime;
CHECK(decode_format->findString("mime", &mime));
bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
...
}
先來看看NuMediaExtractor的一段代碼:
status_t NuMediaExtractor::setDataSource(
const char *path, const KeyedVector<String8, String8> *headers) {
Mutex::Autolock autoLock(mLock);
if (mImpl != NULL) {
return -EINVAL;
}
sp<DataSource> dataSource =
DataSource::CreateFromURI(path, headers);
if (dataSource == NULL) {
return -ENOENT;
}
mIsWidevineExtractor = false;
if (!strncasecmp("widevine://", path, 11)) {
String8 mimeType;
float confidence;
sp<AMessage> dummy;
bool success = SniffWVM(dataSource, &mimeType, &confidence, &dummy);
if (!success || strcasecmp(mimeType.string(), MEDIA_MIMETYPE_CONTAINER_WVM)) {
return ERROR_UNSUPPORTED;
}
sp<WVMExtractor> extractor = new WVMExtractor(dataSource);
extractor->setAdaptiveStreamingMode(true);
mImpl = extractor;
mIsWidevineExtractor = true;
} else {
mImpl = MediaExtractor::Create(dataSource);
}
if (mImpl == NULL) {
return ERROR_UNSUPPORTED;
}
sp<MetaData> fileMeta = mImpl->getMetaData();
const char *containerMime;
if (fileMeta != NULL
&& fileMeta->findCString(kKeyMIMEType, &containerMime)
&& !strcasecmp(containerMime, "video/wvm")) {
static_cast<WVMExtractor *>(mImpl.get())->setCryptoPluginMode(true);
} else if (mImpl->getDrmFlag()) {
// For all other drm content, we don't want to expose decrypted
// content to Java application.
mImpl.clear();
mImpl = NULL;
return ERROR_UNSUPPORTED;
}
mDataSource = dataSource;
updateDurationAndBitrate();
return OK;
}
DataSource通過path的類型創(chuàng)建出匹配的資源:
sp<DataSource> DataSource::CreateFromURI(
const char *uri, const KeyedVector<String8, String8> *headers) {
bool isWidevine = !strncasecmp("widevine://", uri, 11);
sp<DataSource> source;
if (!strncasecmp("file://", uri, 7)) {
source = new FileSource(uri + 7);
setFileName(uri + 7);
} else if (!strncasecmp("http://", uri, 7)
|| !strncasecmp("https://", uri, 8)
|| isWidevine) {
sp<HTTPBase> httpSource = HTTPBase::Create();
String8 tmp;
if (isWidevine) {
tmp = String8("http://");
tmp.append(uri + 11);
uri = tmp.string();
}
if (httpSource->connect(uri, headers) != OK) {
return NULL;
}
if (!isWidevine) {
String8 cacheConfig;
bool disconnectAtHighwatermark;
if (headers != NULL) {
KeyedVector<String8, String8> copy = *headers;
NuCachedSource2::RemoveCacheSpecificHeaders(
©, &cacheConfig, &disconnectAtHighwatermark);
}
source = new NuCachedSource2(
httpSource,
cacheConfig.isEmpty() ? NULL : cacheConfig.string());
} else {
source = httpSource;
}
# if CHROMIUM_AVAILABLE
} else if (!strncasecmp("data:", uri, 5)) {
source = createDataUriSource(uri);
#endif
} else {
// Assume it's a filename.
source = new FileSource(uri);
setFileName(uri);
}
if (source == NULL || source->initCheck() != OK) {
return NULL;
}
return source;
}
假如當(dāng)前的path傳入的是http://的網(wǎng)絡(luò)資源串磕蒲,那么就會實例化一個HTTPBase對象.首先看一下HTTPBase的聲明:
struct HTTPBase : public DataSource {
enum Flags {
// Don't log any URLs.
kFlagIncognito = 1
};
HTTPBase();
...
}
從代碼中可以看到稠屠,通過createChromiumHTTPDataSource來創(chuàng)建了一個HTTPBase 對象的指針:
sp<HTTPBase> HTTPBase::Create(uint32_t flags) {
#if CHROMIUM_AVAILABLE
HTTPBase *dataSource = createChromiumHTTPDataSource(flags);
if (dataSource) {
return dataSource;
}
#endif
{
TRESPASS();
return NULL;
}
}
createChromiumHTTPDataSource在libstagefright的chromium_http模塊中,調(diào)用代碼:
chromium_http_stub.h
#ifndef CHROMIUM_HTTP_STUB_H_
#define CHROMIUM_HTTP_STUB_H_
#include <include/HTTPBase.h>
#include <media/stagefright/DataSource.h>
namespace android {
extern "C" {
HTTPBase *createChromiumHTTPDataSource(uint32_t flags);
status_t UpdateChromiumHTTPDataSourceProxyConfig(
const char *host, int32_t port, const char *exclusionList);
DataSource *createDataUriSource(const char *uri);
}
}
#endif
chromium_http_stub.cpp
HTTPBase *(*gLib_createChromiumHTTPDataSource)(uint32_t flags);
DataSource *(*gLib_createDataUriSource)(const char *uri);
static bool load_libstagefright_chromium_http() {
Mutex::Autolock autoLock(gLibMutex);
void *sym;
if (!gFirst) {
return (gHandle != NULL);
}
gFirst = false;
gHandle = dlopen("libstagefright_chromium_http.so", RTLD_NOW);
if (gHandle == NULL) {
return false;
}
sym = dlsym(gHandle, "createChromiumHTTPDataSource");
if (sym == NULL) {
gHandle = NULL;
return false;
}gLib_createChromiumHTTPDataSource = (HTTPBase *(*)(uint32_t))sym;
sym = dlsym(gHandle, "createDataUriSource");
if (sym == NULL) {
gHandle = NULL;
return false;
}
gLib_createDataUriSource = (DataSource *(*)(const char *))sym;
...
}
HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
if (!load_libstagefright_chromium_http()) {
return NULL;
}
return gLib_createChromiumHTTPDataSource(flags);
}
libstagefright_chromium_http.so就是libstagefright的chromium_http模塊了:
#include <dlfcn.h>
#include <include/chromium_http_stub.h>
#include <include/ChromiumHTTPDataSource.h>
#include <include/DataUriSource.h>
namespace android {
HTTPBase *createChromiumHTTPDataSource(uint32_t flags) {
return new ChromiumHTTPDataSource(flags);
}
status_t UpdateChromiumHTTPDataSourceProxyConfig(
const char *host, int32_t port, const char *exclusionList) {
return ChromiumHTTPDataSource::UpdateProxyConfig(host, port, exclusionList);
}
DataSource *createDataUriSource(const char *uri) {
return new DataUriSource(uri);
}
ChromiumHTTPDataSource.cpp
ChromiumHTTPDataSource::ChromiumHTTPDataSource(uint32_t flags)
: mFlags(flags),
mState(DISCONNECTED),
mDelegate(new SfDelegate),
mCurrentOffset(0),
mIOResult(OK),
mContentSize(-1),
mDecryptHandle(NULL),
mDrmManagerClient(NULL) {
mDelegate->setOwner(this);
}
ChromiumHTTPDataSource::~ChromiumHTTPDataSource() {
disconnect();
delete mDelegate;
mDelegate = NULL;
clearDRMState_l();
if (mDrmManagerClient != NULL) {
delete mDrmManagerClient;
mDrmManagerClient = NULL;
}
}
那么httpSource->connect(uri, headers)做了些什么韧骗?
status_t ChromiumHTTPDataSource::connect(
const char *uri,
const KeyedVector<String8, String8> *headers,
off64_t offset) {
Mutex::Autolock autoLock(mLock);
uid_t uid;
if (getUID(&uid)) {
mDelegate->setUID(uid);
}
#if defined(LOG_NDEBUG) && !LOG_NDEBUG
LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG, "connect on behalf of uid %d", uid);
#endif
return connect_l(uri, headers, offset);
}
status_t ChromiumHTTPDataSource::connect_l(
const char *uri,
const KeyedVector<String8, String8> *headers,
off64_t offset) {
if (mState != DISCONNECTED) {
disconnect_l();
}
#if defined(LOG_NDEBUG) && !LOG_NDEBUG
LOG_PRI(ANDROID_LOG_VERBOSE, LOG_TAG,
"connect to <URL suppressed> @%lld", offset);
#endif
mURI = uri;
mContentType = String8("application/octet-stream");
if (headers != NULL) {
mHeaders = *headers;
} else {
mHeaders.clear();
}
mState = CONNECTING;
mContentSize = -1;
mCurrentOffset = offset;
mDelegate->initiateConnection(mURI.c_str(), &mHeaders, offset);
while (mState == CONNECTING || mState == DISCONNECTING) {
mCondition.wait(mLock);
}
return mState == CONNECTED ? OK : mIOResult;
}
在chromium_http模塊中SfDelegate繼承了net::URLRequest::Delegate代理所有http的處理:
struct SfDelegate : public net::URLRequest::Delegate {
...
}
net::URLRequest::Delegate是libchromium_net的實現(xiàn)嘉抒,可以去看external\chromium下的代碼,MK文件如下:
###################################
# Build the libchromium_net library
LOCAL_PATH := $(call my-dir)
include external/chromium/third_party/libevent/Android.mk
include external/chromium/third_party/modp_b64/Android.mk
include external/chromium/base/third_party/dmg_fp/Android.mk
include $(CLEAR_VARS)
LOCAL_CPP_EXTENSION := .cc
LOCAL_MODULE := libchromium_net
LOCAL_MODULE_CLASS := SHARED_LIBRARIES
INTERMEDIATES := $(call local-intermediates-dir)
LOCAL_SRC_FILES := \
googleurl/src/gurl.cc \
googleurl/src/url_canon_etc.cc \
googleurl/src/url_canon_fileurl.cc \
googleurl/src/url_canon_host.cc \
googleurl/src/url_canon_icu.cc \
googleurl/src/url_canon_internal.cc \
googleurl/src/url_canon_ip.cc \
googleurl/src/url_canon_mailtourl.cc \
googleurl/src/url_canon_path.cc \
googleurl/src/url_canon_pathurl.cc \
googleurl/src/url_canon_query.cc \
googleurl/src/url_canon_relative.cc \
googleurl/src/url_canon_stdurl.cc \
googleurl/src/url_parse.cc \
googleurl/src/url_parse_file.cc \
googleurl/src/url_util.cc \
\
android/content/common/url_constants.cc \
android/execinfo.cc \
android/jni/autofill_request_url.cc \
android/jni/mime_utils.cc \
android/jni/jni_utils.cc \
android/jni/platform_file_jni.cc \
android/net/android_network_library_impl.cc \
android/ui/base/l10n/l10n_util.cc \
\
app/sql/connection.cc \
app/sql/meta_table.cc \
app/sql/statement.cc \
app/sql/transaction.cc \
ifeq ($(TARGET_ARCH),x86)
LOCAL_SRC_FILES += \
base/atomicops_internals_x86_gcc.cc
endif
LOCAL_SRC_FILES += \
base/at_exit.cc \
base/base64.cc \
base/environment.cc \
base/file_descriptor_shuffle.cc \
base/file_path.cc \
base/file_util.cc \
base/file_util_posix.cc \
base/lazy_instance.cc \
base/logging.cc \
base/message_loop.cc \
base/message_loop_proxy.cc \
base/message_loop_proxy_impl.cc \
base/message_pump.cc \
base/message_pump_default.cc \
base/message_pump_libevent.cc \
base/md5.cc \
base/native_library_linux.cc \
base/pickle.cc \
base/platform_file.cc \
base/platform_file_posix.cc \
base/process_posix.cc \
base/process_util.cc \
base/process_util_linux.cc \
base/process_util_posix.cc \
base/rand_util.cc \
base/rand_util_posix.cc \
base/safe_strerror_posix.cc \
base/sha1_portable.cc \
base/shared_memory_posix.cc \
base/string_number_conversions.cc \
base/string_piece.cc \
base/string_split.cc \
base/string_util.cc \
base/string16.cc \
base/stringprintf.cc \
base/sys_info_linux.cc \
base/sys_info_posix.cc \
base/sys_string_conversions_linux.cc \
base/task.cc \
base/time.cc \
base/time_posix.cc \
base/timer.cc \
base/tracked.cc \
base/tracked_objects.cc \
base/utf_offset_string_conversions.cc \
base/utf_string_conversions.cc \
base/utf_string_conversion_utils.cc \
base/values.cc \
base/vlog.cc \
\
base/debug/debugger_posix.cc \
base/debug/stack_trace.cc \
base/debug/stack_trace_posix.cc \
\
base/i18n/file_util_icu.cc \
base/i18n/icu_string_conversions.cc \
base/i18n/time_formatting.cc \
\
base/json/json_reader.cc \
base/json/json_writer.cc \
base/json/string_escape.cc \
\
base/memory/ref_counted.cc \
base/memory/weak_ptr.cc \
\
base/metrics/field_trial.cc \
base/metrics/histogram.cc \
base/metrics/stats_counters.cc \
base/metrics/stats_table.cc \
\
base/synchronization/cancellation_flag.cc \
base/synchronization/condition_variable_posix.cc \
base/synchronization/lock_impl_posix.cc \
base/synchronization/waitable_event_posix.cc \
\
base/threading/platform_thread_posix.cc \
base/threading/thread.cc \
base/threading/thread_checker_impl.cc \
base/threading/thread_collision_warner.cc \
base/threading/thread_local_posix.cc \
base/threading/thread_local_storage_posix.cc \
base/threading/worker_pool_posix.cc \
\
base/third_party/icu/icu_utf.cc \
\
base/third_party/nspr/prtime.cc \
\
chrome/browser/net/sqlite_persistent_cookie_store.cc \
\
crypto/openssl_util.cc \
crypto/secure_hash_default.cc \
crypto/sha2.cc \
\
crypto/third_party/nss/sha512.cc \
\
net/base/address_list.cc \
net/base/address_list_net_log_param.cc \
net/base/android_network_library.cc \
net/base/auth.cc \
net/base/backoff_entry.cc \
net/base/bandwidth_metrics.cc \
net/base/capturing_net_log.cc \
net/base/cert_database.cc \
net/base/cert_status_flags.cc \
net/base/cert_verifier.cc \
net/base/cert_verify_result.cc \
net/base/connection_type_histograms.cc \
net/base/cookie_monster.cc \
net/base/cookie_store.cc \
net/base/data_url.cc \
net/base/directory_lister.cc \
net/base/dns_util.cc \
net/base/dnsrr_resolver.cc \
net/base/escape.cc \
net/base/file_stream_posix.cc \
net/base/filter.cc \
net/base/gzip_filter.cc \
net/base/gzip_header.cc \
net/base/host_cache.cc \
net/base/host_mapping_rules.cc \
net/base/host_port_pair.cc \
net/base/host_resolver.cc \
net/base/host_resolver_impl.cc \
net/base/host_resolver_proc.cc \
net/base/io_buffer.cc \
net/base/ip_endpoint.cc \
net/base/mime_util.cc \
net/base/net_errors.cc \
net/base/net_errors_posix.cc \
net/base/net_log.cc \
net/base/net_module.cc \
net/base/net_util.cc \
net/base/net_util_posix.cc \
net/base/network_change_notifier.cc \
net/base/network_change_notifier_linux.cc \
net/base/network_change_notifier_netlink_linux.cc \
net/base/network_delegate.cc \
net/base/openssl_memory_private_key_store.cc \
net/base/pem_tokenizer.cc \
net/base/platform_mime_util_android.cc \
net/base/registry_controlled_domain.cc \
net/base/sdch_manager.cc \
net/base/sdch_filter.cc \
net/base/ssl_cert_request_info.cc \
net/base/ssl_client_auth_cache.cc \
net/base/ssl_config_service.cc \
net/base/ssl_config_service_defaults.cc \
net/base/ssl_info.cc \
net/base/transport_security_state.cc \
net/base/upload_data.cc \
net/base/upload_data_stream.cc \
net/base/x509_cert_types.cc \
net/base/x509_certificate.cc \
net/base/x509_certificate_openssl.cc \
net/base/x509_certificate_openssl_android.cc \
net/base/x509_openssl_util.cc \
\
net/disk_cache/addr.cc \
net/disk_cache/backend_impl.cc \
net/disk_cache/bitmap.cc \
net/disk_cache/block_files.cc \
net/disk_cache/cache_util_posix.cc \
net/disk_cache/disk_format.cc \
net/disk_cache/entry_impl.cc \
net/disk_cache/eviction.cc \
net/disk_cache/file.cc \
net/disk_cache/file_lock.cc \
net/disk_cache/file_posix.cc \
net/disk_cache/hash.cc \
net/disk_cache/in_flight_backend_io.cc \
net/disk_cache/in_flight_io.cc \
net/disk_cache/mapped_file_posix.cc \
net/disk_cache/mem_backend_impl.cc \
net/disk_cache/mem_entry_impl.cc \
net/disk_cache/mem_rankings.cc \
net/disk_cache/net_log_parameters.cc \
net/disk_cache/rankings.cc \
net/disk_cache/stats.cc \
net/disk_cache/stats_histogram.cc \
net/disk_cache/sparse_control.cc \
net/disk_cache/trace.cc \
\
net/ftp/ftp_auth_cache.cc \
\
net/http/des.cc \
net/http/disk_cache_based_ssl_host_info.cc \
net/http/http_alternate_protocols.cc \
net/http/http_auth.cc \
net/http/http_auth_cache.cc \
net/http/http_auth_controller.cc \
net/http/http_auth_gssapi_posix.cc \
net/http/http_auth_handler.cc \
net/http/http_auth_handler_basic.cc \
net/http/http_auth_handler_digest.cc \
net/http/http_auth_handler_factory.cc \
net/http/http_auth_handler_negotiate.cc \
net/http/http_auth_handler_ntlm.cc \
net/http/http_auth_handler_ntlm_portable.cc \
net/http/http_basic_stream.cc \
net/http/http_byte_range.cc \
net/http/http_cache.cc \
net/http/http_cache_transaction.cc \
net/http/http_chunked_decoder.cc \
net/http/http_net_log_params.cc \
net/http/http_network_layer.cc \
net/http/http_network_session.cc \
net/http/http_network_transaction.cc \
net/http/http_proxy_client_socket.cc \
net/http/http_proxy_client_socket_pool.cc \
net/http/http_proxy_utils.cc \
net/http/http_request_headers.cc \
net/http/http_request_info.cc \
net/http/http_response_body_drainer.cc \
net/http/http_response_headers.cc \
net/http/http_response_info.cc \
net/http/http_stream_factory.cc \
net/http/http_stream_factory_impl.cc \
net/http/http_stream_factory_impl_job.cc \
net/http/http_stream_factory_impl_request.cc \
net/http/http_stream_parser.cc \
net/http/http_util.cc \
net/http/http_util_icu.cc \
net/http/http_vary_data.cc \
net/http/md4.cc \
net/http/partial_data.cc \
\
net/proxy/init_proxy_resolver.cc \
net/proxy/multi_threaded_proxy_resolver.cc \
net/proxy/proxy_bypass_rules.cc \
net/proxy/proxy_config.cc \
net/proxy/proxy_config_service_android.cc \
net/proxy/proxy_config_service_fixed.cc \
net/proxy/proxy_info.cc \
net/proxy/proxy_list.cc \
net/proxy/proxy_resolver_js_bindings.cc \
net/proxy/proxy_resolver_script_data.cc \
net/proxy/proxy_server.cc \
net/proxy/proxy_service.cc \
net/proxy/sync_host_resolver_bridge.cc \
\
net/socket/client_socket.cc \
net/socket/client_socket_handle.cc \
net/socket/client_socket_factory.cc \
net/socket/client_socket_pool.cc \
net/socket/client_socket_pool_base.cc \
net/socket/client_socket_pool_histograms.cc \
net/socket/client_socket_pool_manager.cc \
net/socket/socks_client_socket.cc \
net/socket/socks_client_socket_pool.cc \
net/socket/socks5_client_socket.cc \
net/socket/ssl_client_socket.cc \
net/socket/ssl_client_socket_openssl.cc \
net/socket/ssl_client_socket_pool.cc \
net/socket/ssl_error_params.cc \
net/socket/ssl_host_info.cc \
net/socket/tcp_client_socket.cc \
net/socket/tcp_client_socket_libevent.cc \
net/socket/transport_client_socket_pool.cc \
\
net/spdy/spdy_framer.cc \
net/spdy/spdy_frame_builder.cc \
net/spdy/spdy_http_stream.cc \
net/spdy/spdy_http_utils.cc \
net/spdy/spdy_io_buffer.cc \
net/spdy/spdy_proxy_client_socket.cc \
net/spdy/spdy_session.cc \
net/spdy/spdy_session_pool.cc \
net/spdy/spdy_settings_storage.cc \
net/spdy/spdy_stream.cc \
\
net/url_request/https_prober.cc \
net/url_request/url_request.cc \
net/url_request/url_request_context.cc \
net/url_request/url_request_context_getter.cc \
net/url_request/url_request_file_job.cc \
net/url_request/url_request_file_dir_job.cc \
net/url_request/url_request_http_job.cc \
net/url_request/url_request_error_job.cc \
net/url_request/url_request_job.cc \
net/url_request/url_request_job_manager.cc \
net/url_request/url_request_job_tracker.cc \
net/url_request/url_request_netlog_params.cc \
net/url_request/url_request_redirect_job.cc \
net/url_request/url_request_throttler_entry.cc \
net/url_request/url_request_throttler_header_adapter.cc \
net/url_request/url_request_throttler_manager.cc \
\
sdch/open-vcdiff/src/addrcache.cc \
sdch/open-vcdiff/src/blockhash.cc \
sdch/open-vcdiff/src/codetable.cc \
sdch/open-vcdiff/src/encodetable.cc \
sdch/open-vcdiff/src/decodetable.cc \
sdch/open-vcdiff/src/headerparser.cc \
sdch/open-vcdiff/src/instruction_map.cc \
sdch/open-vcdiff/src/logging.cc \
sdch/open-vcdiff/src/varint_bigendian.cc \
sdch/open-vcdiff/src/vcdecoder.cc \
sdch/open-vcdiff/src/vcdiffengine.cc \
sdch/open-vcdiff/src/vcencoder.cc \
\
ui/gfx/point.cc \
# AutoFill++ source files.
LOCAL_SRC_FILES += \
android/autofill/android_url_request_context_getter.cc \
android/autofill/profile_android.cc \
android/autofill/url_fetcher_proxy.cc \
\
base/base_paths.cc \
base/base_paths_linux.cc \
base/path_service.cc \
\
chrome/browser/autofill/address.cc \
chrome/browser/autofill/address_field.cc \
chrome/browser/autofill/autofill_country.cc \
chrome/browser/autofill/autofill_download.cc \
chrome/browser/autofill/autofill_field.cc \
chrome/browser/autofill/autofill_manager.cc \
chrome/browser/autofill/autofill_metrics.cc \
chrome/browser/autofill/autofill_profile.cc \
chrome/browser/autofill/autofill_type.cc \
chrome/browser/autofill/autofill_xml_parser.cc \
chrome/browser/autofill/contact_info.cc \
chrome/browser/autofill/credit_card.cc \
chrome/browser/autofill/credit_card_field.cc \
chrome/browser/autofill/fax_number.cc \
chrome/browser/autofill/form_field.cc \
chrome/browser/autofill/form_group.cc \
chrome/browser/autofill/form_structure.cc \
chrome/browser/autofill/name_field.cc \
chrome/browser/autofill/home_phone_number.cc \
chrome/browser/autofill/personal_data_manager.cc \
chrome/browser/autofill/phone_field.cc \
chrome/browser/autofill/phone_number.cc \
chrome/browser/autofill/select_control_handler.cc \
\
chrome/common/guid.cc \
chrome/common/guid_posix.cc \
chrome/common/url_constants.cc \
\
chrome/common/net/url_fetcher.cc \
chrome/common/net/url_fetcher_protect.cc \
\
third_party/libjingle/overrides/talk/xmllite/qname.cc \
third_party/libjingle/source/talk/xmllite/xmlbuilder.cc \
third_party/libjingle/source/talk/xmllite/xmlconstants.cc \
third_party/libjingle/source/talk/xmllite/xmlelement.cc \
third_party/libjingle/source/talk/xmllite/xmlnsstack.cc \
third_party/libjingle/source/talk/xmllite/xmlparser.cc \
third_party/libjingle/source/talk/xmllite/xmlprinter.cc \
\
webkit/glue/form_data.cc \
webkit/glue/form_field.cc
LOCAL_C_INCLUDES := \
$(LOCAL_PATH) \
$(LOCAL_PATH)/chrome \
$(LOCAL_PATH)/chrome/browser \
$(LOCAL_PATH)/sdch/open-vcdiff/src \
$(LOCAL_PATH)/third_party/libevent/compat \
external/expat \
external/icu4c/common \
external/icu4c/i18n \
external/openssl/include \
external/skia \
external/sqlite/dist \
external/webkit/Source/WebKit/chromium \
external/zlib \
external \
$(LOCAL_PATH)/base/third_party/dmg_fp \
$(LOCAL_PATH)/third_party/icu/public/common \
$(LOCAL_PATH)/third_party/libevent/android \
$(LOCAL_PATH)/third_party/libevent \
$(LOCAL_PATH)/third_party/libjingle/overrides \
$(LOCAL_PATH)/third_party/libjingle/source \
vendor/google/libraries/autofill
# Chromium uses several third party libraries and headers that are already
# present on Android, but in different include paths. Generate a set of
# forwarding headers in the location that Chromium expects.
THIRD_PARTY = $(INTERMEDIATES)/third_party
SCRIPT := $(LOCAL_PATH)/android/generateAndroidForwardingHeader.pl
GEN := $(THIRD_PARTY)/expat/files/lib/expat.h
$(GEN): $(SCRIPT)
$(GEN):
perl $(SCRIPT) $@ "lib/expat.h"
LOCAL_GENERATED_SOURCES += $(GEN)
GEN := $(THIRD_PARTY)/skia/include/core/SkBitmap.h
$(GEN): $(SCRIPT)
$(GEN):
perl $(SCRIPT) $@ "include/core/SkBitmap.h"
LOCAL_GENERATED_SOURCES += $(GEN)
GEN := $(THIRD_PARTY)/WebKit/Source/WebKit/chromium/public/WebFormControlElement.h
$(GEN): $(SCRIPT)
$(GEN):
perl $(SCRIPT) $@ "public/WebFormControlElement.h"
LOCAL_GENERATED_SOURCES += $(GEN)
GEN := $(THIRD_PARTY)/WebKit/Source/WebKit/chromium/public/WebRegularExpression.h
$(GEN): $(SCRIPT)
$(GEN):
perl $(SCRIPT) $@ "public/WebRegularExpression.h"
LOCAL_GENERATED_SOURCES += $(GEN)
GEN := $(THIRD_PARTY)/WebKit/Source/WebKit/chromium/public/WebString.h
$(GEN): $(SCRIPT)
$(GEN):
perl $(SCRIPT) $@ "public/WebString.h"
LOCAL_GENERATED_SOURCES += $(GEN)
LOCAL_CFLAGS := -DHAVE_CONFIG_H -DANDROID -DEXPAT_RELATIVE_PATH -DALLOW_QUOTED_COOKIE_VALUES -DCOMPONENT_BUILD -DGURL_DLL
LOCAL_CPPFLAGS := -Wno-sign-promo -Wno-missing-field-initializers -fvisibility=hidden -fvisibility-inlines-hidden
# Just a few definitions not provided by bionic.
LOCAL_CFLAGS += -include "android/prefix.h"
# external/chromium/android is a directory to intercept stl headers that we do
# not support yet.
LOCAL_C_INCLUDES := \
$(LOCAL_PATH)/android \
$(LOCAL_C_INCLUDES)
LOCAL_STATIC_LIBRARIES := libevent modp_b64 dmg_fp
LOCAL_SHARED_LIBRARIES := libstlport libexpat libcrypto libssl libz libicuuc libicui18n libsqlite libcutils liblog libdl
LOCAL_PRELINK_MODULE := false
# Including this will modify the include path
include external/stlport/libstlport.mk
ifneq ($(strip $(WITH_ADDRESS_SANITIZER)),)
LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/asan
LOCAL_ADDRESS_SANITIZER := true
endif
include $(BUILD_SHARED_LIBRARY)
可以看到libchromium_net對net已經(jīng)實現(xiàn)很多關(guān)于http袍暴、disk_cache些侍、proxy、socket等網(wǎng)絡(luò)處理容诬。本篇文章不涉及該模塊內(nèi)容娩梨。
connect對http請求做了初始化處理,然后委托給NuCachedSource2
source = new NuCachedSource2(
httpSource,
cacheConfig.isEmpty() ? NULL : cacheConfig.string());
NuCachedSource2是一個帶緩存的DataSource览徒,通過調(diào)用底層的 DataSource讀取和緩存數(shù)據(jù)狈定。也就是說NuMediaExtractor委托NuCachedSource2,而NuCachedSource2委托HTTPBase 习蓬, HTTPBase又委托ChromiumHTTPDataSource纽什, ChromiumHTTPDataSource又委托給SfDelegate去完成http連接的發(fā)起和關(guān)閉,反過來通過注冊的回調(diào)函數(shù)(onConnectionEstablished, onDisconnectComplete等)來獲取連接信息躲叼。
根據(jù)代碼實現(xiàn)經(jīng)驗創(chuàng)建一個MediaExtractor后芦缰,再配置資源,然后就可以獲取流(文件或網(wǎng)絡(luò))的Format數(shù)據(jù)枫慷。
sp<NuMediaExtractor> extractor = new NuMediaExtractor;
if (extractor->setDataSource(path) != OK) {
fprintf(stderr, "unable to instantiate extractor.\n");
extractor = NULL;
return 1;
}
for (size_t i = 0; i < extractor->countTracks(); ++i) {
sp<AMessage> decode_format;
status_t err = extractor->getTrackFormat(i, &decode_format);
CHECK_EQ(err, (status_t)OK);
AString mime;
CHECK(decode_format->findString("mime", &mime));
bool isAudio = !strncasecmp(mime.c_str(), "audio/", 6);
bool isVideo = !strncasecmp(mime.c_str(), "video/", 6);
...
}
結(jié)合之前的代碼分析让蕾,在NuMediaExtractor::setDataSource中根據(jù)path創(chuàng)建一個DataSource的指針后,然后就是通過DataSource實例化 MediaExtractor或听,以http://為例:
status_t NuMediaExtractor::setDataSource(
const char *path, const KeyedVector<String8, String8> *headers) {
...
sp<DataSource> dataSource =
DataSource::CreateFromURI(path, headers);
...
mImpl = MediaExtractor::Create(dataSource);
}
sp<DataSource> DataSource::CreateFromURI(
const char *uri, const KeyedVector<String8, String8> *headers) {
...
sp<HTTPBase> httpSource = HTTPBase::Create();
...
if (httpSource->connect(uri, headers) != OK) {
return NULL;
}
...
source = httpSource;
...
if (source == NULL || source->initCheck() != OK) {
return NULL;
}
return source;
}
sp<MediaExtractor> MediaExtractor::Create(
const sp<DataSource> &source, const char *mime) {
sp<AMessage> meta;
String8 tmp;
if (mime == NULL) {
float confidence;
if (!source->sniff(&tmp, &confidence, &meta)) {
ALOGV("FAILED to autodetect media content.");
return NULL;
}
mime = tmp.string();
ALOGV("Autodetected media content as '%s' with confidence %.2f",
mime, confidence);
}
bool isDrm = false;
// DRM MIME type syntax is "drm+type+original" where
// type is "es_based" or "container_based" and
// original is the content's cleartext MIME type
if (!strncmp(mime, "drm+", 4)) {
const char *originalMime = strchr(mime+4, '+');
if (originalMime == NULL) {
// second + not found
return NULL;
}
++originalMime;
if (!strncmp(mime, "drm+es_based+", 13)) {
// DRMExtractor sets container metadata kKeyIsDRM to 1
return new DRMExtractor(source, originalMime);
} else if (!strncmp(mime, "drm+container_based+", 20)) {
mime = originalMime;
isDrm = true;
} else {
return NULL;
}
}
MediaExtractor *ret = NULL;
if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG4)
|| !strcasecmp(mime, "audio/mp4")) {
ret = new MPEG4Extractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_MPEG)) {
ret = new MP3Extractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)
|| !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) {
ret = new AMRExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) {
ret = new FLACExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WAV)) {
ret = new WAVExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_OGG)) {
ret = new OggExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MATROSKA)) {
ret = new MatroskaExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2TS)) {
ret = new MPEG2TSExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_WVM)) {
// Return now. WVExtractor should not have the DrmFlag set in the block below.
return new WVMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_PR)) {
// SSPRExtractor for playready
return new SStreamingExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADTS)) {
ret = new AACExtractor(source, meta);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_ADIF)) {
ret = new ADIFExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC_LATM)) {
ret = new LATMExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_ADTS_PROFILE)) {
ret = new ADTSExtractor(source);
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_MPEG2PS)) {
ret = new MPEG2PSExtractor(source);
} else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_WMA)||!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_WMAPRO)){
ret = new AsfExtractor(source);
}else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_DTSHD)){
ret = new DtshdExtractor(source);
} else if(!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_AIFF)){
ret = new AIFFExtractor(source);
} else if(!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_TRUEHD)){
ret = new THDExtractor(source);
}
#ifdef DOLBY_UDC
else if (!strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_DDP)) {
ret = new DDPExtractor(source);
}
#endif
if (ret != NULL) {
if (isDrm) {
ret->setDrmFlag(true);
} else {
ret->setDrmFlag(false);
}
}
return ret;
}
DRM是數(shù)字版權(quán)管理模塊探孝,可直接跳過不用分析,核心在于通過source->sniff獲取流的元數(shù)據(jù)誉裆,然后根據(jù)元數(shù)據(jù)的描述實例化對應(yīng)的Extractor顿颅,從上面的代碼中可以看到Extractor包括但不限于MPEG4Extractor、MP3Extractor足丢、AMRExtractor粱腻、AACExtractor、MPEG2TSExtractor等斩跌,我們也可以在這個地方創(chuàng)建自定義的Extractor绍些,(分析到這里,我感覺Extractor的設(shè)計模式和ExoPlayer有點像了)滔驶。
那么source->sniff到底做了什么遇革?我們以TS流為例:
void DataSource::RegisterDefaultSniffers() {
Mutex::Autolock autoLock(gSnifferMutex);
if (gSniffersRegistered) {
return;
}
RegisterSniffer_l(SniffADTS);
RegisterSniffer_l(SniffMPEG4);
RegisterSniffer_l(SniffMatroska);
RegisterSniffer_l(SniffOgg);
RegisterSniffer_l(SniffWAV);
RegisterSniffer_l(SniffFLAC);
RegisterSniffer_l(SniffAMR);
RegisterSniffer_l(SniffMPEG2TS);
RegisterSniffer_l(SniffMP3);
RegisterSniffer_l(SniffAAC);
RegisterSniffer_l(SniffADIF);
RegisterSniffer_l(SniffLATM);
RegisterSniffer_l(SniffMPEG2PS);
RegisterSniffer_l(SniffWVM);
RegisterSniffer_l(SniffAsf);
RegisterSniffer_l(SniffAIFF);
RegisterSniffer_l(SniffTHD);
RegisterSniffer_l(SniffDcahd);
char value[PROPERTY_VALUE_MAX];
if (property_get("drm.service.enabled", value, NULL)
&& (!strcmp(value, "1") || !strcasecmp(value, "true"))) {
RegisterSniffer_l(SniffDRM);
}
gSniffersRegistered = true;
}
我們看SniffMPEG2TS的實現(xiàn):
bool SniffMPEG2TS(
const sp<DataSource> &source, String8 *mimeType, float *confidence,
sp<AMessage> *) {
for (int i = 0; i < 5; ++i) {
char header;
if (source->readAt(kTSPacketSize * i, &header, 1) != 1
|| header != 0x47) {
return false;
}
}
*confidence = 0.1f;
mimeType->setTo(MEDIA_MIMETYPE_CONTAINER_MPEG2TS);
return true;
}
分析到這里,我們就知道該如何創(chuàng)建匹配的Extractor了,通過DataSource去讀取一個數(shù)據(jù)包的大小(ts為188字節(jié))萝快,校驗讀取的Buffer(ts包的第一個字節(jié)為0x47)锻霎,匹配校驗規(guī)則的就可以配置對應(yīng)的Extractor。這里說的DataSource以http://為例揪漩,結(jié)合之前的代碼分析旋恼,其實就是交給了chromium_http去處理(本文就不再深入分析):
ssize_t ChromiumHTTPDataSource::readAt(off64_t offset, void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
if (mState != CONNECTED) {
return INVALID_OPERATION;
}
if (offset != mCurrentOffset) {
AString tmp = mURI;
KeyedVector<String8, String8> tmpHeaders = mHeaders;
disconnect_l();
status_t err = connect_l(tmp.c_str(), &tmpHeaders, offset);
if (err != OK) {
return err;
}
}
mState = READING;
int64_t startTimeUs = ALooper::GetNowUs();
mDelegate->initiateRead(data, size);
while (mState == READING) {
mCondition.wait(mLock);
}
if (mIOResult < OK) {
return mIOResult;
}
if (mState == CONNECTED) {
int64_t delayUs = ALooper::GetNowUs() - startTimeUs;
// The read operation was successful, mIOResult contains
// the number of bytes read.
addBandwidthMeasurement(mIOResult, delayUs);
mCurrentOffset += mIOResult;
return mIOResult;
}
return ERROR_IO;
}
實例化Extractor,以TS為例:
MPEG2TSExtractor::MPEG2TSExtractor(const sp<DataSource> &source)
: mDataSource(source),
mParser(new ATSParser),
mOffset(0) {
init();
}
void MPEG2TSExtractor::init() {
bool haveAudio = false;
bool haveVideo = false;
int numPacketsParsed = 0;
while (feedMore() == OK) {
ATSParser::SourceType type;
if (haveAudio && haveVideo) {
break;
}
if (!haveVideo) {
sp<AnotherPacketSource> impl =
(AnotherPacketSource *)mParser->getSource(
ATSParser::VIDEO).get();
if (impl != NULL) {
haveVideo = true;
mSourceImpls.push(impl);
}
}
if (!haveAudio) {
sp<AnotherPacketSource> impl =
(AnotherPacketSource *)mParser->getSource(
ATSParser::AUDIO).get();
if (impl != NULL) {
haveAudio = true;
mSourceImpls.push(impl);
}
}
if (++numPacketsParsed > 10000) {
break;
}
}
ALOGI("haveAudio=%d, haveVideo=%d", haveAudio, haveVideo);
}
status_t MPEG2TSExtractor::feedMore() {
Mutex::Autolock autoLock(mLock);
uint8_t packet[kTSPacketSize];
ssize_t n = mDataSource->readAt(mOffset, packet, kTSPacketSize);
if (n < (ssize_t)kTSPacketSize) {
return (n < 0) ? (status_t)n : ERROR_END_OF_STREAM;
}
mOffset += n;
return mParser->feedTSPacket(packet, kTSPacketSize);
}
可以看到都是從DataSource::readAt讀取指定長度的buffer奄容,然后做相應(yīng)的處理冰更,那么讀取到數(shù)據(jù)后,通過Extractor獲取到video/audio的信息也就不難了昂勒。
實例化Extractor后蜀细,就是獲取Format信息了,比如getTrackFormat:
status_t NuMediaExtractor::getTrackFormat(
size_t index, sp<AMessage> *format) const {
Mutex::Autolock autoLock(mLock);
*format = NULL;
if (mImpl == NULL) {
return -EINVAL;
}
if (index >= mImpl->countTracks()) {
return -ERANGE;
}
sp<MetaData> meta = mImpl->getTrackMetaData(index);
return convertMetaDataToMessage(meta, format);
}
size_t MPEG2TSExtractor::countTracks() {
return mSourceImpls.size();
}
sp<MetaData> MPEG2TSExtractor::getTrackMetaData(
size_t index, uint32_t flags) {
return index < mSourceImpls.size()
? mSourceImpls.editItemAt(index)->getFormat() : NULL;
}
從上面的代碼可以知道戈盈,通過調(diào)用MediaExtractor的API奠衔,都是通過從DataSource獲取數(shù)據(jù),然后通過Extractor實例化對相應(yīng)數(shù)據(jù)做處理或回調(diào)塘娶,分析到這里就越是覺得和ExoPlayer的設(shè)計模式相同了归斤。
3.結(jié)束語
關(guān)于MediaExtractor的實現(xiàn)分析告一段落,由于之前有過對Exoplayer中Extractor有過分析刁岸,所以這里理解起來會好梳理些脏里。如果可以,建議兩篇文章一起分析虹曙,感謝持續(xù)關(guān)注迫横!