Đường hầm đa phương tiện

Đường hầm đa phương tiện cho phép dữ liệu video nén chuyển qua bộ giải mã video phần cứng trực tiếp tới màn hình mà không cần 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 xác định khung hình video nào sẽ gửi tới màn hình và thời điểm gửi chúng bằng cách so sánh dấu thời gian trình bày khung video với một trong các loại đồng hồ bên trong sau:

  • Để phát lại video theo yêu cầu trong Android 5 trở lên, đồng hồ AudioTrack được đồng bộ hóa với dấu thời gian của bản trình bày âm thanh được ứng dụng chuyển vào

  • Để 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ộ dò điều khiển

Lý lịch

Tính năng phát lại video truyền thống trên Android sẽ thông báo cho ứng dụng khi khung video nén đã được giải mã. Sau đó, ứng dụng sẽ đưa khung video đã giải mã ra màn hình để hiển thị ở cùng thời gian đồng hồ hệ thống với khung âm thanh tương ứng, truy xuất các phiên bản AudioTimestamps lịch sử để tính toán thời gian chính xác.

Vì tính năng phát lại video theo đường hầm bỏ qua mã ứng dụng và giảm số lượng quy trình tác động lên video nên tính năng này có thể cung cấp kết xuất video hiệu quả hơn tùy thuộc vào việc triển khai OEM. Nó cũng có thể cung cấp nhịp điệu và đồng bộ hóa 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 yêu cầu Android hiển thị video và thời gian của vsyncs phần cứng thực sự. 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 như làm mờ hoặc bo tròn các góc trong cửa sổ hình trong hình (PiP), vì bộ đệm bỏ qua ngăn xếp đồ họa của Android.

Sơ đồ sau đây cho thấy cách tạo đường hầm giúp đơn giản hóa quá trình phát lại video.

so sánh phương thức truyền thống và đường hầm

Hình 1. So sánh quy trình phát lại video truyền thống và đường hầm

Dành cho nhà phát triển ứng dụng

Bởi vì hầu hết các nhà phát triển ứng dụng đều tích hợp với thư viện để triển khai phát lại, nên trong hầu hết các trường hợp, việc triển khai chỉ yêu cầu cấu hình lại thư viện đó để phát lại theo đường hầm. Để triển khai trình phát video dạng đường hầm ở cấp độ thấp, hãy sử dụng các hướng dẫn sau.

Để phát lại video theo yêu cầu trong Android 5 trở lên:

  1. Tạo một phiên bản SurfaceView .

  2. Tạo một phiên bản audioSessionId .

  3. Tạo phiên bản AudioTrackMediaCodec bằng phiên bản audioSessionId được tạo ở bước 2.

  4. Xếp hàng dữ liệu âm thanh vào AudioTrack với dấu thời gian trình bày cho khung âm thanh đầu tiên trong dữ liệu âm thanh.

Để phát lại chương trình phát sóng trực tiếp trên Android 11 trở lên:

  1. Tạo một phiên bản SurfaceView .

  2. Nhận phiên bản avSyncHwId từ Tuner .

  3. Tạo phiên bản AudioTrackMediaCodec bằng phiên bản avSyncHwId được tạo ở bước 2.

Luồng lệnh gọi API được hiển thị 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 lại video theo yêu cầu

Vì tính năng phát lại video theo đường hầm được gắn hoàn toàn với tính năng phát lại AudioTrack nên hoạt động phát lại video theo đường hầm có thể phụ thuộc vào hoạt động phát lại âm thanh.

  • Theo mặc định, trên hầu hết các thiết bị, khung hình video không được hiển thị cho đến khi bắt đầu phát lại âm thanh. Tuy nhiên, ứng dụng có thể cần hiển thị khung video trước khi bắt đầu phát lại âm thanh, chẳng hạn như để hiển thị cho người dùng vị trí video hiện tại trong khi tìm kiếm.

    • Để báo hiệu rằng khung video được xếp hàng đầu tiên sẽ được hiển thị ngay sau khi được giải mã, hãy đặt tham số PARAMETER_KEY_TUNNEL_PEEK thành 1 . 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 được hiển thị đầu tiên phải luôn là khung hình I.

    • Nếu bạn không muốn hiển thị khung hình video được xếp hàng đầu tiên cho đến khi bắt đầu phát lại âm thanh, hãy đặt tham số này thành 0 .

    • Nếu tham số này không được đặt, 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à bộ đệm trống (âm thanh bị thiếu), quá trình phát lại video sẽ dừng lại cho đến khi có thêm dữ liệu âm thanh được ghi vì đồng hồ âm thanh không còn tăng nữa.

  • Trong quá trình phát lại, những điểm gián đoạn mà ứng dụng không thể sửa được có thể xuất hiện trong dấu thời gian của bản trình bày âm thanh. Khi điều này xảy ra, OEM sẽ khắc phục 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à các khoảng trống tích cực bằng cách bỏ khung hình video hoặc chèn các khung âm thanh im lặng (tùy thuộc vào việc triển khai OEM). Vị trí khung AudioTimestamp không tăng đối với các khung â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ợ phát lại video theo đường hầm. Bộ giải mã này phải quảng cáo rằng nó có khả năng phát lại theo đường hầm trong tệp media_codecs.xml :

<Feature name="tunneled-playback" required="true"/>

Khi một phiên bản MediaCodec đường hầm được định cấu hình với ID phiên âm thanh, nó sẽ truy vấn AudioFlinger để tìm ID 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 truy xuất ID HW_AV_SYNC từ thiết bị âm thanh chính và liên kết nội bộ nó với ID phiên âm thanh:

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 phiên bản AudioTrack đã được tạo thì ID HW_AV_SYNC sẽ được chuyển đến luồng đầu ra có cùng ID phiên âm thanh. Nếu nó chưa được tạo thì ID HW_AV_SYNC sẽ được chuyển đến luồng đầu ra trong quá trình tạo AudioTrack . Điều này được thực hiện bởi luồng phát lại :

mOutput->stream->common.set_parameters(&mOutput->stream->common, AUDIO_PARAMETER_STREAM_HW_AV_SYNC, hwAVSyncId);

ID HW_AV_SYNC , cho dù tương ứng với luồng đầu ra âm thanh hay cấu hình Tuner chỉnh, đều được chuyển vào thành phần OMX hoặc Codec2 để mã OEM có thể liên kết codec với luồng đầu ra âm thanh tương ứng hoặc luồng bộ điều 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 bộ điều khiển dải bên có thể được sử dụng để liên kết codec với lớp Trình soạn thảo phần cứng (HWC). Khi ứng dụng liên kết một bề mặt với MediaCodec , tay cầm dải bên này sẽ được chuyển xuống HWC thông qua SurfaceFlinger , cấu hình này sẽ định cấu hình lớp này thành lớp dải bên .

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 bộ đệm hình ảnh mới từ đầu ra codec vào thời điểm thích hợp, được đồng bộ hóa với luồng đầu ra âm thanh liên quan hoặc đồng hồ tham chiếu chương trình bộ điều chỉnh, tổng hợp bộ đệ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 thu được. Điều này xảy ra độc lập với chu trình chuẩn bị và thiết lập thông thường. Lệnh gọi chuẩn bị và thiết lập 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 dải bên (chẳng hạn như vị trí hoặc kích thước) thay đổi.

OMX

Thành phần bộ giải mã đường hầm phải hỗ trợ các tính năng sau:

  • Đặt tham số mở rộng OMX.google.android.index.configureVideoTunnelMode , tham số này sử dụng cấu trúc ConfigureVideoTunnelModeParams để chuyển ID HW_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 để yêu cầu codec hiển thị hoặc không hiển thị khung video được giải mã đầu tiên, bất kể quá trình phát lại âm thanh đã bắt đầu hay chưa.

  • Gửi sự kiện OMX_EventOnFirstTunnelFrameReady khi khung video được tạo đường hầm đầu tiên đã được giải mã và sẵn sàng hiển thị.

Việc triển khai AOSP định cấu hình chế độ đường hầm trong ACodec thông qua OMXNodeInstance như 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, nó sẽ phân bổ một bộ điều khiển dải bên cho codec này và chuyển nó trở lại thành viên pSidebandWindow để HWC có thể xác định codec liên quan. Nếu thành phần không hỗ trợ cấu hình này, nó sẽ đặt bTunneled thành OMX_FALSE .

Codec2

Trong Android 11 trở lên, Codec2 hỗ trợ phát lại theo đường hầm. Thành phần bộ giải mã phải hỗ trợ những điều sau:

  • Định cấu hình C2PortTunneledModeTuning , cấu hình chế độ đường hầm và chuyển HW_AV_SYNC được truy xuất từ ​​thiết bị đầu ra âm thanh hoặc cấu hình bộ dò.

  • Truy vấn C2_PARAMKEY_OUTPUT_TUNNEL_HANDLE , để phân bổ và truy xuất bộ điều khiển dải bên cho HWC.

  • Xử lý C2_PARAMKEY_TUNNEL_HOLD_RENDER khi được gắn vào C2Work , hướng dẫn codec giải mã và báo hiệu hoàn thành công việc, nhưng không hiển thị bộ đệm đầu ra cho đến khi 1) codec sau đó được hướng dẫn hiển thị hoặc 2) quá trình phát lại âm thanh bắt đầu.

  • Xử lý C2_PARAMKEY_TUNNEL_START_RENDER , hướng dẫn codec hiển thị ngay lập tức khung được đánh dấu bằng C2_PARAMKEY_TUNNEL_HOLD_RENDER , ngay cả khi quá trình phát lại âm thanh chưa bắt đầu.

  • Không định cấu debug.stagefright.ccodec_delayed_params (được khuyến nghị). Nếu bạn định cấu hình nó, hãy đặt thành false .

Việc triển khai AOSP định cấu hình chế độ đường hầm trong CCodec thông qua C2PortTunnelModeTuning , như minh họa 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, &params);
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, nó sẽ phân bổ một bộ điều khiển dải bên cho codec này và chuyển nó trở lại C2PortTunnelHandlingTuning để HWC có thể xác định codec liên quan.

Âm thanh HAL

Để phát lại video theo yêu cầu, Audio HAL nhận dấu thời gian trình bày âm thanh cùng dòng với dữ liệu âm thanh ở định dạng big-endian bên trong tiêu đề được tìm thấy ở đầ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 hiển thị các khung hình video đồng bộ với các khung âm thanh tương ứng, Audio HAL phải phân tích tiêu đề đồng bộ hóa và sử dụng dấu thời gian của bản trình bày để đồng bộ hóa lại đồng hồ phát lại với kết xuất âm thanh. Để đồng bộ hóa lại khi âm thanh nén đang được phát, Audio HAL có thể cần phân tích siêu dữ liệu bên trong dữ liệu âm thanh nén để xác định thời lượng phát lại.

Tạm dừng hỗ trợ

Android 5 trở xuống không bao gồm hỗ trợ tạm dừng. Bạn chỉ có thể tạm dừng phát lại theo đường hầm bằng cách bỏ đói A/V, nhưng nếu bộ đệm bên trong dành cho video lớn (ví dụ: có một giây dữ liệu trong thành phần OMX), thì điều đó khiến cho việc tạm dừng 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 (đường hầm). Nếu HAL thực hiện tạm dừng và tiếp tục, việc tạm dừng và tiếp tục theo dõi sẽ được chuyển tiếp đến HAL.

Trình tự tạm dừng, xóa, tiếp tục cuộc gọi được tôn trọng bằng cách thực hiện các lệnh gọi HAL trong chuỗi phát lại (giống như giảm tải).

Đề xuất thực hiện

Âm thanh HAL

Đối với Android 11, ID đồng bộ hóa CTNH từ PCR hoặc STC có thể được sử dụng để đồng bộ hóa A/V, do đó, chỉ hỗ trợ luồng video.

Đối với Android 10 trở xuống, các thiết bị hỗ trợ phát lại video qua đường hầm phải có ít nhất một cấu hình luồng đầu ra âm thanh có cờ FLAG_HW_AV_SYNCAUDIO_OUTPUT_FLAG_DIRECT trong tệp audio_policy.conf . Những cờ này được sử dụng để đặt đồng hồ hệ thống từ đồng hồ âm thanh.

OMX

Các nhà sản xuất thiết bị nên có thành phần OMX riêng để phát lại video theo đường hầm (các nhà sản xuất có thể có các thành phần OMX bổ sung cho các loại phát lại âm thanh và video khác, chẳng hạn như phát lại an toàn). Thành phần đường hầm nên:

  • Chỉ định 0 bộ đệm ( nBufferCountMin , nBufferCountActual ) trên cổng đầu ra của nó.

  • Triển khai tiện ích mở rộng OMX.google.android.index.prepareForAdaptivePlayback setParameter .

  • Chỉ định các khả năng của nó trong tệp media_codecs.xml và khai báo tính năng phát lại theo đường hầm. Nó cũng cần làm rõ mọi hạn chế về kích thước khung hình, căn chỉnh hoặc tốc độ bit. Một ví dụ đã được biểu diễn ở dưới:

    <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 sử dụng cùng một thành phần OMX để hỗ trợ giải mã có đường hầm và không có đường hầm thì tính năng phát lại có đường hầm là không bắt buộc. Cả hai bộ giải mã có đường hầm và không có đường hầm đều có những hạn chế về khả năng giống nhau. Một ví dụ đã được biểu diễn ở dưới:

<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>

Trình soạn thảo phần cứng (HWC)

Khi có một lớp được tạo đường hầm (một lớp có HWC_SIDEBAND compositionType ) trên màn hình, sidebandStream của lớp đó là bộ điều khiển dải bên được phân bổ bởi thành phần video OMX.

HWC đồng bộ hóa các khung hình video đã giải mã (từ thành phần OMX được tạo đường hầm) đến rãnh âm thanh liên quan (với ID audio-hw-sync ). Khi một khung video mới trở thà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 cuối cùng và hiển thị hình ảnh kết quả. 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 dải bên (chẳng hạn như vị trí hoặc kích thước) thay đổi.

Hình dưới đây biểu thị HWC làm việc với bộ đồng bộ hóa phần cứng (hoặc hạt 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).

HWC kết hợp các khung hình video dựa trên âm thanh

Hình 2. Bộ đồng bộ hóa phần cứng (hoặc kernel hoặc trình điều khiển) HWC