1.介绍:
MediaExtractor是Android中音视频解复用器,可以将video和audio分离出来。android kitkat版本上支持本地和http的音视频解复用,打算按照这个设计模式扩展电信IPTV的RTSP的音视频解复用。
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的类型创建出匹配的资源:
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;
}
假如当前的path传入的是http://的网络资源串,那么就会实例化一个HTTPBase对象.首先看一下HTTPBase的声明:
struct HTTPBase : public DataSource {
enum Flags {
// Don't log any URLs.
kFlagIncognito = 1
};
HTTPBase();
...
}
从代码中可以看到,通过createChromiumHTTPDataSource来创建了一个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模块中,调用代码:
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的实现,可以去看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已经实现很多关于http、disk_cache、proxy、socket等网络处理。本篇文章不涉及该模块内容。
connect对http请求做了初始化处理,然后委托给NuCachedSource2
source = new NuCachedSource2(
httpSource,
cacheConfig.isEmpty() ? NULL : cacheConfig.string());
NuCachedSource2是一个带缓存的DataSource,通过调用底层的 DataSource读取和缓存数据。也就是说NuMediaExtractor委托NuCachedSource2,而NuCachedSource2委托HTTPBase , HTTPBase又委托ChromiumHTTPDataSource, ChromiumHTTPDataSource又委托给SfDelegate去完成http连接的发起和关闭,反过来通过注册的回调函数(onConnectionEstablished, onDisconnectComplete等)来获取连接信息。
根据代码实现经验创建一个MediaExtractor后,再配置资源,然后就可以获取流(文件或网络)的Format数据。
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::setDataSource中根据path创建一个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是数字版权管理模块,可直接跳过不用分析,核心在于通过source->sniff获取流的元数据,然后根据元数据的描述实例化对应的Extractor,从上面的代码中可以看到Extractor包括但不限于MPEG4Extractor、MP3Extractor、AMRExtractor、AACExtractor、MPEG2TSExtractor等,我们也可以在这个地方创建自定义的Extractor,(分析到这里,我感觉Extractor的设计模式和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的实现:
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;
}
分析到这里,我们就知道该如何创建匹配的Extractor了,通过DataSource去读取一个数据包的大小(ts为188字节),校验读取的Buffer(ts包的第一个字节为0x47),匹配校验规则的就可以配置对应的Extractor。这里说的DataSource以http://为例,结合之前的代码分析,其实就是交给了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,然后做相应的处理,那么读取到数据后,通过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;
}
从上面的代码可以知道,通过调用MediaExtractor的API,都是通过从DataSource获取数据,然后通过Extractor实例化对相应数据做处理或回调,分析到这里就越是觉得和ExoPlayer的设计模式相同了。
3.结束语
关于MediaExtractor的实现分析告一段落,由于之前有过对Exoplayer中Extractor有过分析,所以这里理解起来会好梳理些。如果可以,建议两篇文章一起分析,感谢持续关注!