Tính năng truyền dữ liệu đa phương tiện qua đường hầm cho phép dữ liệu video nén truyền qua đường hầm từ bộ giải mã video phần cứng trực tiếp đến màn hình mà không cần được xử lý bằng mã ứng dụng hoặc mã khung Android. Mã dành riêng cho thiết bị bên dưới ngăn xếp Android sẽ xác định khung hình video nào cần gửi đến màn hình và thời điểm gửi bằng cách so sánh dấu thời gian trình bày khung hình video với một trong các loại đồng hồ nội bộ sau:
Đối với chế độ phát video theo yêu cầu trong Android 5 trở lên, đồng hồ
AudioTrack
được đồng bộ hoá với dấu thời gian trình bày âm thanh được truyền trong ứng dụngĐối với hoạt động phát lại chương trình phát sóng trực tiếp trên Android 11 trở lên, đồng hồ tham chiếu chương trình (PCR) hoặc đồng hồ thời gian hệ thống (STC) do bộ chỉnh kênh điều khiển
Thông tin khái quát
Chế độ phát video truyền thống trên Android thông báo cho ứng dụng khi một khung hình video nén đã được giải mã. Sau đó, ứng dụng sẽ phát khung hình video đã giải mã lên màn hình để hiển thị tại cùng thời điểm đồng hồ hệ thống với khung hình âm thanh tương ứng, truy xuất các phiên bản AudioTimestamps
trước đây để tính toán thời gian chính xác.
Vì chế độ phát video được chuyển hướng bỏ qua mã ứng dụng và giảm số lượng quy trình tác động lên video, nên chế độ này có thể mang lại hiệu suất kết xuất video hiệu quả hơn, tuỳ thuộc vào cách triển khai của OEM. Thư viện này cũng có thể cung cấp nhịp điệu và khả năng đồng bộ hoá video chính xác hơn với đồng hồ đã chọn (PRC, STC hoặc âm thanh) bằng cách tránh các vấn đề về thời gian do độ lệch tiềm ẩn giữa thời gian của các yêu cầu Android để kết xuất video và thời gian của các lệnh vsync phần cứng thực. Tuy nhiên, việc tạo đường hầm cũng có thể làm giảm khả năng hỗ trợ các hiệu ứng GPU, chẳng hạn như làm mờ hoặc bo tròn góc trong cửa sổ hình trong hình (PiP), vì các vùng đệm bỏ qua ngăn xếp đồ hoạ Android.
Sơ đồ sau đây cho thấy cách tính năng truyền dữ liệu qua đường hầm giúp đơn giản hoá quy trình phát video.
Hình 1. So sánh quy trình phát video truyền thống và quy trình phát video qua đường hầm
Dành cho nhà phát triển ứng dụng
Vì hầu hết nhà phát triển ứng dụng đều tích hợp với một thư viện để triển khai tính năng phát, nên trong hầu hết các trường hợp, việc triển khai chỉ yêu cầu định cấu hình lại thư viện đó cho tính năng phát qua đường hầm. Để triển khai trình phát video được chuyển hướng ở cấp thấp, hãy làm theo hướng dẫn sau.
Đối với chế độ phát video theo yêu cầu trong Android 5 trở lên:
Tạo một thực thể
SurfaceView
.Tạo một thực thể
audioSessionId
.Tạo các thực thể
AudioTrack
vàMediaCodec
bằng thực thểaudioSessionId
được tạo ở bước 2.Xếp hàng dữ liệu âm thanh vào
AudioTrack
bằng dấu thời gian trình bày cho khung âm thanh đầu tiên trong dữ liệu âm thanh.
Đối với chế độ phát lại chương trình phát sóng trực tiếp trên Android 11 trở lên:
Tạo một thực thể
SurfaceView
.Nhận một thực thể
avSyncHwId
từTuner
.Tạo các thực thể
AudioTrack
vàMediaCodec
bằng thực thểavSyncHwId
được tạo ở bước 2.
Luồng gọi API được minh hoạ trong các đoạn mã sau:
aab.setContentType(AudioAttributes.CONTENT_TYPE_MOVIE);
// configure for audio clock sync
aab.setFlag(AudioAttributes.FLAG_HW_AV_SYNC);
// or, for tuner clock sync (Android 11 or higher)
new tunerConfig = TunerConfiguration(0, avSyncId);
aab.setTunerConfiguration(tunerConfig);
if (codecName == null) {
return FAILURE;
}
// configure for audio clock sync
mf.setInteger(MediaFormat.KEY_AUDIO_SESSION_ID, audioSessionId);
// or, for tuner clock sync (Android 11 or higher)
mf.setInteger(MediaFormat.KEY_HARDWARE_AV_SYNC_ID, avSyncId);
Hành vi phát video theo yêu cầu
Vì tính năng phát video theo yêu cầu được truyền qua đường hầm có liên kết ngầm với hoạt động phát AudioTrack
, nên hành vi phát video được truyền qua đường hầm có thể phụ thuộc vào hành vi phát âm thanh.
Theo mặc định, trên hầu hết các thiết bị, khung hình video sẽ không được kết xuất cho đến khi quá trình phát âm thanh bắt đầu. Tuy nhiên, ứng dụng có thể cần kết xuất một khung hình video trước khi bắt đầu phát âm thanh, ví dụ: để cho người dùng thấy vị trí hiện tại của video trong khi tìm kiếm.
Để báo hiệu rằng khung hình video đầu tiên trong hàng đợi sẽ được hiển thị ngay khi được giải mã, hãy đặt tham số
PARAMETER_KEY_TUNNEL_PEEK
thành1
. Khi các khung hình video nén được sắp xếp lại trong hàng đợi (chẳng hạn như khi có khung hình B), điều này có nghĩa là khung hình video đầu tiên được hiển thị phải luôn là khung hình I.Nếu bạn không muốn khung hình video đầu tiên trong hàng đợi được kết xuất cho đến khi quá trình phát âm thanh bắt đầu, hãy đặt tham số này thành
0
.Nếu bạn không đặt tham số này, thì OEM sẽ xác định hành vi cho thiết bị.
Khi dữ liệu âm thanh không được cung cấp cho
AudioTrack
và các vùng đệm trống (thiếu dữ liệu âm thanh), quá trình phát video sẽ bị tạm dừng cho đến khi có thêm dữ liệu âm thanh được ghi vì đồng hồ âm thanh không còn hoạt động.Trong quá trình phát, những điểm gián đoạn mà ứng dụng không thể khắc phục có thể xuất hiện trong dấu thời gian trình bày âm thanh. Khi điều này xảy ra, OEM sẽ điều chỉnh các khoảng trống tiêu cực bằng cách tạm dừng khung hình video hiện tại và điều chỉnh các khoảng trống tích cực bằng cách loại bỏ khung hình video hoặc chèn khung hình âm thanh im lặng (tuỳ thuộc vào cách triển khai của OEM). Vị trí khung hình
AudioTimestamp
không tăng đối với các khung hình âm thanh im lặng được chèn.
Dành cho nhà sản xuất thiết bị
Cấu hình
Các OEM nên tạo một bộ giải mã video riêng để hỗ trợ tính năng phát video qua đường hầm.
Bộ giải mã này phải thông báo rằng bộ giải mã có khả năng phát qua đường hầm trong tệp media_codecs.xml
:
<Feature name="tunneled-playback" required="true"/>
Khi một thực thể MediaCodec
được chuyển kênh được định cấu hình bằng mã phiên âm thanh, thực thể đó sẽ truy vấn AudioFlinger
cho mã HW_AV_SYNC
này:
if (entry.getKey().equals(MediaFormat.KEY_AUDIO_SESSION_ID)) {
int sessionId = 0;
try {
sessionId = (Integer)entry.getValue();
}
catch (Exception e) {
throw new IllegalArgumentException("Wrong Session ID Parameter!");
}
keys[i] = "audio-hw-sync";
values[i] = AudioSystem.getAudioHwSyncForSession(sessionId);
}
Trong truy vấn này, AudioFlinger
sẽ truy xuất mã nhận dạng HW_AV_SYNC
từ thiết bị âm thanh chính và liên kết mã nhận dạng đó với mã nhận dạng phiên âm thanh theo cách nội bộ:
audio_hw_device_t *dev = mPrimaryHardwareDev->hwDevice();
char *reply = dev->get_parameters(dev, AUDIO_PARAMETER_HW_AV_SYNC);
AudioParameter param = AudioParameter(String8(reply));
int hwAVSyncId;
param.getInt(String8(AUDIO_PARAMETER_HW_AV_SYNC), hwAVSyncId);
Nếu một phiên bản AudioTrack
đã được tạo, thì mã nhận dạng HW_AV_SYNC
sẽ được truyền đến luồng đầu ra có cùng mã phiên âm thanh. Nếu chưa được tạo, thì mã nhận dạng HW_AV_SYNC
sẽ được truyền đến luồng đầu ra trong quá trình tạo AudioTrack
. Việc này được thực hiện bằng luồng phát:
mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);
Mã nhận dạng HW_AV_SYNC
, cho dù mã nhận dạng đó tương ứng với luồng đầu ra âm thanh hay cấu hình Tuner
, đều được truyền vào thành phần OMX hoặc Codec2 để mã OEM có thể liên kết bộ mã hoá và giải mã với luồng đầu ra âm thanh tương ứng hoặc luồng bộ chỉnh.
Trong quá trình định cấu hình thành phần, thành phần OMX hoặc Codec2 sẽ trả về một giá trị nhận dạng phụ có thể dùng để liên kết bộ mã hoá và giải mã với một lớp Hardware Composer (HWC). Khi ứng dụng liên kết một vùng hiển thị với MediaCodec
, đối tượng điều khiển phụ này sẽ được truyền xuống HWC thông qua SurfaceFlinger
, đối tượng này sẽ định cấu hình lớp dưới dạng lớp phụ.
err = native_window_set_sideband_stream(nativeWindow.get(), sidebandHandle);
if (err != OK) {
ALOGE("native_window_set_sideband_stream(%p) failed! (err %d).", sidebandHandle, err);
return err;
}
HWC chịu trách nhiệm nhận các vùng đệm hình ảnh mới từ đầu ra của bộ mã hoá và giải mã vào thời điểm thích hợp, được đồng bộ hoá với luồng đầu ra âm thanh được liên kết hoặc đồng hồ tham chiếu chương trình của bộ chỉnh, kết hợp các vùng đệm với nội dung hiện tại của các lớp khác và hiển thị hình ảnh kết quả. Điều này xảy ra độc lập với chu kỳ chuẩn bị và thiết lập thông thường. Các lệnh gọi chuẩn bị và đặt chỉ xảy ra khi các lớp khác thay đổi hoặc khi các thuộc tính của lớp sideband (chẳng hạn như vị trí hoặc kích thước) thay đổi.
OMX
Thành phần bộ giải mã được chuyển hướng qua đường hầm phải hỗ trợ những nội dung sau:
Đặt tham số mở rộng
OMX.google.android.index.configureVideoTunnelMode
, sử dụng cấu trúcConfigureVideoTunnelModeParams
để truyền trong mã nhận dạngHW_AV_SYNC
được liên kết với thiết bị đầu ra âm thanh.Định cấu hình tham số
OMX_IndexConfigAndroidTunnelPeek
để cho biết codec có hiển thị hay không hiển thị khung hình video được giải mã đầu tiên, bất kể quá trình phát âm thanh đã bắt đầu hay chưa.Gửi sự kiện
OMX_EventOnFirstTunnelFrameReady
khi khung hình video được truyền qua đường hầm đầu tiên đã được giải mã và sẵn sàng hiển thị.
Quá trình triển khai AOSP sẽ định cấu hình chế độ đường hầm trong ACodec
thông qua OMXNodeInstance
như minh hoạ trong đoạn mã sau:
OMX_INDEXTYPE index;
OMX_STRING name = const_cast<OMX_STRING>(
"OMX.google.android.index.configureVideoTunnelMode");
OMX_ERRORTYPE err = OMX_GetExtensionIndex(mHandle, name, &index);
ConfigureVideoTunnelModeParams tunnelParams;
InitOMXParams(&tunnelParams);
tunnelParams.nPortIndex = portIndex;
tunnelParams.bTunneled = tunneled;
tunnelParams.nAudioHwSync = audioHwSync;
err = OMX_SetParameter(mHandle, index, &tunnelParams);
err = OMX_GetParameter(mHandle, index, &tunnelParams);
sidebandHandle = (native_handle_t*)tunnelParams.pSidebandWindow;
Nếu thành phần hỗ trợ cấu hình này, thì thành phần đó sẽ phân bổ một giá trị nhận dạng phụ cho codec này và truyền giá trị nhận dạng đó trở lại thông qua thành phần pSidebandWindow
để HWC có thể xác định codec được liên kết. Nếu thành phần không hỗ trợ cấu hình này, thì thành phần đó sẽ đặt bTunneled
thành OMX_FALSE
.
Codec2
Trên Android 11 trở lên, Codec2
hỗ trợ chế độ phát qua đường hầm. Thành phần bộ giải mã phải hỗ trợ những nội dung sau:
Định cấu hình
C2PortTunneledModeTuning
, định cấu hình chế độ đường hầm và truyền trongHW_AV_SYNC
được truy xuất từ thiết bị đầu ra âm thanh hoặc cấu hình bộ chỉnh.Truy vấn
C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE
để phân bổ và truy xuất ô điều khiển phụ cho HWC.Xử lý
C2_PARAMKEY_TUNNEL_HOLD_RENDER
khi được đính kèm vàoC2Work
, hướng dẫn bộ mã hoá và giải mã giải mã và báo hiệu hoàn tất công việc, nhưng không hiển thị vùng đệm đầu ra cho đến khi 1) bộ mã hoá và giải mã được hướng dẫn hiển thị vùng đệm đó sau hoặc 2) quá trình phát âm thanh bắt đầu.Xử lý
C2_PARAMKEY_TUNNEL_START_RENDER
, hướng dẫn bộ mã hoá và giải mã kết xuất ngay khung hình được đánh dấu bằngC2_PARAMKEY_TUNNEL_HOLD_RENDER
, ngay cả khi quá trình phát âm thanh chưa bắt đầu.Để
debug.stagefright.ccodec_delayed_params
ở trạng thái chưa định cấu hình (nên dùng). Nếu bạn định cấu hình, hãy đặt thànhfalse
.
Quá trình triển khai AOSP định cấu hình chế độ đường hầm trong CCodec
thông qua C2PortTunnelModeTuning
, như minh hoạ trong đoạn mã sau:
if (msg->findInt32("audio-hw-sync", &tunneledPlayback->m.syncId[0])) {
tunneledPlayback->m.syncType =
C2PortTunneledModeTuning::Struct::sync_type_t::AUDIO_HW_SYNC;
} else if (msg->findInt32("hw-av-sync-id", &tunneledPlayback->m.syncId[0])) {
tunneledPlayback->m.syncType =
C2PortTunneledModeTuning::Struct::sync_type_t::HW_AV_SYNC;
} else {
tunneledPlayback->m.syncType =
C2PortTunneledModeTuning::Struct::sync_type_t::REALTIME;
tunneledPlayback->setFlexCount(0);
}
c2_status_t c2err = comp->config({ tunneledPlayback.get() }, C2_MAY_BLOCK,
failures);
std::vector<std::unique_ptr<C2Param>> params;
c2err = comp->query({}, {C2PortTunnelHandleTuning::output::PARAM_TYPE},
C2_DONT_BLOCK, ¶ms);
if (c2err == C2_OK && params.size() == 1u) {
C2PortTunnelHandleTuning::output *videoTunnelSideband =
C2PortTunnelHandleTuning::output::From(params[0].get());
return OK;
}
Nếu thành phần hỗ trợ cấu hình này, thì thành phần đó sẽ phân bổ một chỉ báo phụ cho codec này và truyền chỉ báo đó trở lại thông qua C2PortTunnelHandlingTuning
để HWC có thể xác định codec được liên kết.
HAL âm thanh
Đối với chế độ phát video theo yêu cầu, Audio HAL nhận các dấu thời gian trình chiếu âm thanh cùng với dữ liệu âm thanh ở định dạng big-endian bên trong một tiêu đề nằm ở đầu mỗi khối dữ liệu âm thanh mà ứng dụng ghi:
struct TunnelModeSyncHeader {
// The 32-bit data to identify the sync header (0x55550002)
int32 syncWord;
// The size of the audio data following the sync header before the next sync
// header might be found.
int32 sizeInBytes;
// The presentation timestamp of the first audio sample following the sync
// header.
int64 presentationTimestamp;
// The number of bytes to skip after the beginning of the sync header to find the
// first audio sample (20 bytes for compressed audio, or larger for PCM, aligned
// to the channel count and sample size).
int32 offset;
}
Để HWC kết xuất các khung hình video đồng bộ với các khung hình âm thanh tương ứng, Audio HAL phải phân tích cú pháp tiêu đề đồng bộ hoá và sử dụng dấu thời gian trình bày để đồng bộ hoá lại đồng hồ phát với quá trình kết xuất âm thanh. Để đồng bộ hoá lại khi âm thanh nén đang phát, Audio HAL có thể cần phân tích cú pháp siêu dữ liệu bên trong dữ liệu âm thanh nén để xác định thời lượng phát.
Tạm dừng hỗ trợ
Android 5 trở xuống không hỗ trợ tính năng tạm dừng. Bạn chỉ có thể tạm dừng quá trình phát được chuyển hướng bằng cách thiếu A/V, nhưng nếu bộ nhớ đệm nội bộ cho video có kích thước lớn (ví dụ: có một giây dữ liệu trong thành phần OMX), thì thao tác tạm dừng sẽ có vẻ không phản hồi.
Trong Android 5.1 trở lên, AudioFlinger
hỗ trợ tạm dừng và tiếp tục cho đầu ra âm thanh trực tiếp (được truyền qua đường hầm). Nếu HAL triển khai tính năng tạm dừng và tiếp tục, thì lệnh tạm dừng và tiếp tục theo dõi sẽ được chuyển tiếp đến HAL.
Trình tự gọi tạm dừng, xoá, tiếp tục được tuân thủ bằng cách thực thi các lệnh gọi HAL trong luồng phát (tương tự như lệnh gọi chuyển tải).
Đề xuất triển khai
HAL âm thanh
Đối với Android 11, bạn có thể sử dụng mã nhận dạng đồng bộ hoá phần cứng từ PCR hoặc STC để đồng bộ hoá âm thanh/hình ảnh, vì vậy, hệ thống có hỗ trợ luồng chỉ có video.
Đối với Android 10 trở xuống, các thiết bị hỗ trợ chế độ phát video qua đường hầm phải có ít nhất một hồ sơ luồng đầu ra âm thanh có cờ FLAG_HW_AV_SYNC
và AUDIO_OUTPUT_FLAG_DIRECT
trong tệp audio_policy.conf
. Các cờ này được dùng để đặt đồng hồ hệ thống từ đồng hồ âm thanh.
OMX
Nhà sản xuất thiết bị nên có một thành phần OMX riêng để phát video theo đường hầm (nhà sản xuất có thể có các thành phần OMX bổ sung cho các loại phát âm thanh và video khác, chẳng hạn như phát an toàn). Thành phần được chuyển hầm phải:
Chỉ định 0 vùng đệm (
nBufferCountMin
,nBufferCountActual
) trên cổng đầu ra của vùng đệm.Triển khai tiện ích
OMX.google.android.index.prepareForAdaptivePlayback setParameter
.Chỉ định các chức năng của tính năng này trong tệp
media_codecs.xml
và khai báo tính năng phát qua đường hầm. Bạn cũng nên nêu rõ mọi hạn chế về kích thước khung hình, căn chỉnh hoặc tốc độ bit. Sau đây là ví dụ minh hoạ:<MediaCodec name="OMX.OEM_NAME.VIDEO.DECODER.AVC.tunneled" type="video/avc" > <Feature name="adaptive-playback" /> <Feature name="tunneled-playback" required=”true” /> <Limit name="size" min="32x32" max="3840x2160" /> <Limit name="alignment" value="2x2" /> <Limit name="bitrate" range="1-20000000" /> ... </MediaCodec>
Nếu cùng một thành phần OMX được dùng để hỗ trợ việc giải mã có đường hầm và không có đường hầm, thì thành phần đó sẽ để tính năng phát có đường hầm ở trạng thái không bắt buộc. Cả bộ giải mã được chuyển hướng và không được chuyển hướng đều có cùng các hạn chế về khả năng. Sau đây là ví dụ minh hoạ:
<MediaCodec name="OMX._OEM\_NAME_.VIDEO.DECODER.AVC" type="video/avc" >
<Feature name="adaptive-playback" />
<Feature name="tunneled-playback" />
<Limit name="size" min="32x32" max="3840x2160" />
<Limit name="alignment" value="2x2" />
<Limit name="bitrate" range="1-20000000" />
...
</MediaCodec>
Hardware Composer (HWC)
Khi có một lớp được chuyển hướng (lớp có HWC_SIDEBAND
compositionType
) trên màn hình, sidebandStream
của lớp đó là tay cầm phụ do thành phần video OMX phân bổ.
HWC đồng bộ hoá các khung hình video đã giải mã (từ thành phần OMX được truyền qua đường hầm) với bản âm thanh được liên kết (có mã nhận dạng audio-hw-sync
). Khi một khung hình video mới trở thành khung hình hiện tại, HWC sẽ kết hợp khung hình đó với nội dung hiện tại của tất cả các lớp nhận được trong lệnh gọi chuẩn bị hoặc đặt gần đây nhất và hiển thị hình ảnh kết quả.
Các lệnh gọi chuẩn bị hoặc đặt chỉ xảy ra khi các lớp khác thay đổi hoặc khi các thuộc tính của lớp phụ (chẳng hạn như vị trí hoặc kích thước) thay đổi.
Hình sau đây minh hoạ HWC hoạt động với bộ đồng bộ hoá phần cứng (hoặc nhân hoặc trình điều khiển), để kết hợp các khung hình video (7b) với thành phần mới nhất (7a) để hiển thị vào đúng thời điểm, dựa trên âm thanh (7c).
Hình 2. Bộ đồng bộ hoá phần cứng HWC (hoặc bộ đồng bộ hoá nhân hoặc trình điều khiển)