diff options
author | Mahesh Lanka <mlanka@codeaurora.org> | 2014-03-20 16:04:37 +0530 |
---|---|---|
committer | Steve Kondik <steve@cyngn.com> | 2015-10-13 09:14:20 -1000 |
commit | e20c801118f537471c5443601c8505418eaff159 (patch) | |
tree | 22fcbbb0974bb821926284cffe89b3f9fb897a00 | |
parent | 0e94962e3af8b1dd75c1f4dbb88590c737d7e6d9 (diff) | |
download | android_hardware_qcom_media-e20c801118f537471c5443601c8505418eaff159.tar.gz android_hardware_qcom_media-e20c801118f537471c5443601c8505418eaff159.tar.bz2 android_hardware_qcom_media-e20c801118f537471c5443601c8505418eaff159.zip |
dashplayer: Remove dashplayer and QCMediaPlayer projects.
dashplayer and QCMediaPlayer projects are moved
to external/mm-dash
Change-Id: I828d4877fb8638ad43a438caccb60740ce5245fc
25 files changed, 0 insertions, 13058 deletions
@@ -14,11 +14,4 @@ ifneq ($(filter msm8610 msm8226 msm8974 msm8960 apq8084 mpq8092,$(TARGET_BOARD_P include $(QCOM_MEDIA_ROOT)/libc2dcolorconvert/Android.mk endif -ifneq ($(filter msm8974 msm8960 msm8226 apq8084 mpq8092 msm8610 ,$(TARGET_BOARD_PLATFORM)),) -include $(QCOM_MEDIA_ROOT)/QCMediaPlayer/Android.mk -include $(QCOM_MEDIA_ROOT)/QCMediaPlayer/native/Android.mk -include $(QCOM_MEDIA_ROOT)/dashplayer/Android.mk -include $(QCOM_MEDIA_ROOT)/dashplayer/jni/Android.mk -endif - endif diff --git a/QCMediaPlayer/Android.mk b/QCMediaPlayer/Android.mk deleted file mode 100644 index ec52901d..00000000 --- a/QCMediaPlayer/Android.mk +++ /dev/null @@ -1,27 +0,0 @@ -#/****************************************************************************** -#*@file Android.mk -#*brief Rules for copiling the source files -#* ******************************************************************************/ - -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_MODULE_TAGS := eng - -#LOCAL_SRC_FILES := $(call all-subdir-java-files) -ifeq ($(PLATFORM_VERSION),4.3) -LOCAL_SRC_FILES :=com/qualcomm/qcmedia/QCMediaPlayer.java -else -LOCAL_SRC_FILES :=NonJB/com/qualcomm/qcmedia/QCMediaPlayer.java -endif - -LOCAL_SRC_FILES += com/qualcomm/qcmedia/QCTimedText.java - -LOCAL_MODULE := qcmediaplayer -LOCAL_MODULE_PATH := $(TARGET_OUT_JAVA_LIBRARIES) - -ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS), true) -ifndef TARGET_DISABLE_DASH -include $(BUILD_JAVA_LIBRARY) -endif -endif diff --git a/QCMediaPlayer/NonJB/com/qualcomm/qcmedia/QCMediaPlayer.java b/QCMediaPlayer/NonJB/com/qualcomm/qcmedia/QCMediaPlayer.java deleted file mode 100644 index a93eb160..00000000 --- a/QCMediaPlayer/NonJB/com/qualcomm/qcmedia/QCMediaPlayer.java +++ /dev/null @@ -1,556 +0,0 @@ -/* - * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved. - * - * File: QCMediaPlayer.java - * Description: Snapdragon SDK for Android support class. - * - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.qualcomm.qcmedia; - -import android.media.MediaPlayer; -import android.util.Log; -import android.media.TimedText; -import java.lang.ref.WeakReference; -import com.qualcomm.qcmedia.QCTimedText; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Parcel; -import java.util.HashSet; -import java.io.IOException; -import android.content.Context; -import android.net.Uri; -import java.util.Map; - -/** -* QCMediaPlayer extends MediaPlayer from package android.media and provides -* extended APIs and interfaces to get and set MPD attributes for DASH protocol -* in compatible Snapdragon builds. -*{@hide} -*/ - -public class QCMediaPlayer extends MediaPlayer -{ - private final static String TAG = "QCMediaPlayer"; - private QCMediaEventHandler mEventHandler; - - //Stores the supported keys for getParameter invoke call - public static final HashSet<Integer> VALID_GET_PARAM_KEYS = new HashSet<Integer>(); - static - { - VALID_GET_PARAM_KEYS.add(new Integer(OnMPDAttributeListener.ATTRIBUTES_WHOLE_MPD)); - VALID_GET_PARAM_KEYS.add(new Integer(OnMPDAttributeListener.INVOKE_ID_GET_ATTRIBUTES_TYPE_MPD)); - VALID_GET_PARAM_KEYS.add(new Integer(OnQOEEventListener.ATTRIBUTES_QOE_EVENT_PERIODIC)); - VALID_GET_PARAM_KEYS.add(new Integer(QCMediaPlayer.KEY_DASH_REPOSITION_RANGE)); - } - - public QCMediaPlayer() - { - super(); - Looper looper; - if ((looper = Looper.myLooper()) != null) - { - mEventHandler = new QCMediaEventHandler(this, looper); - } - else if ((looper = Looper.getMainLooper()) != null) - { - mEventHandler = new QCMediaEventHandler(this, looper); - } - else - { - mEventHandler = null; - } - - ePlayerState = MediaPlayerState.PLAYER_IDLE; - - Log.d(TAG, "QCMediaPlayer::QCMediaPlayer"); - } - - public void setDataSource(Context context, Uri uri) - throws IOException, IllegalArgumentException, SecurityException, IllegalStateException - { - Log.d(TAG, "setDataSource"); - super.setDataSource(context, uri); - ePlayerState = MediaPlayerState.PLAYER_INITIALIZED; - TurnOnOffTimedTextListener(); - } - - public void setDataSource(Context context, Uri uri, Map<String, String> headers) - throws IOException, IllegalArgumentException, SecurityException, IllegalStateException - { - Log.d(TAG, "setDataSource"); - super.setDataSource(context, uri, headers); - ePlayerState = MediaPlayerState.PLAYER_INITIALIZED; - TurnOnOffTimedTextListener(); - } - - public void setDataSource(String path) - throws IOException, IllegalArgumentException, SecurityException, IllegalStateException - { - Log.d(TAG, "setDataSource"); - super.setDataSource(path); - ePlayerState = MediaPlayerState.PLAYER_INITIALIZED; - TurnOnOffTimedTextListener(); - } - - public void setDataSource(String path, Map<String, String> headers) - throws IOException, IllegalArgumentException, SecurityException, IllegalStateException - { - Log.d(TAG, "setDataSource"); - super.setDataSource(path, headers); - ePlayerState = MediaPlayerState.PLAYER_INITIALIZED; - TurnOnOffTimedTextListener(); - } - - public void reset() { - Log.d(TAG, "reset"); - super.reset(); - ePlayerState = MediaPlayerState.PLAYER_IDLE; - } - - public void release() { - Log.d(TAG, "release"); - - mQCOnPreparedListener = null; - mOnMPDAttributeListener = null; - mOnQCTimedTextListener = null; - mOnQOEEventListener = null; - - super.release(); - - ePlayerState = MediaPlayerState.PLAYER_IDLE; - } - - public void TurnOnOffTimedTextListener() - { - //Turn on/off timedtext registered flag in dashplayer. setOnQCTimedTextListener can be called - //anytime from app. Below qcsetparameter call uses invoke() which needs to be called only - //after mediaplayer.cpp transitioned out of IDLE state - if(ePlayerState != MediaPlayerState.PLAYER_IDLE) - { - int val = (mOnQCTimedTextListener == null) ? 0 : 1; - Log.d(TAG, "TurnOnOffTimedTextListener set listener flag" + val); - QCsetParameter(KEY_QCTIMEDTEXT_LISTENER, val); - } - } - - private void callOnPreparedListener() - { - Log.d(TAG, "callOnPreparedListener"); - if (mQCOnPreparedListener != null) - mQCOnPreparedListener.onPrepared(this); - } - - private void callOnMPDAttributeListener() - { - Log.d(TAG, "callOnMPDAttributeListener"); - if (mOnMPDAttributeListener != null) - { - String mpdAttributes = QCgetStringParameter(OnMPDAttributeListener.INVOKE_ID_GET_ATTRIBUTES_TYPE_MPD); - mOnMPDAttributeListener.onMPDAttribute(OnMPDAttributeListener.ATTRIBUTES_TYPE_MPD, mpdAttributes, this); - } - } - private void callQCTimedTextListener(QCTimedText text) - { - if(mOnQCTimedTextListener != null) - { - mOnQCTimedTextListener.onQCTimedText(this, text); - } - } - private void callOnQOEEventListener(int key,Parcel parcel) - { - Log.d(TAG, "callOnQOEEventListener"); - if (mOnQOEEventListener != null) - { - mOnQOEEventListener.onQOEAttribute(key,parcel,this); - } - } - - /** - * Additional propreitary interface definition of a callback to be invoked - * when a Qtimed text is available for display. - * {@hide} - */ - public interface OnQCTimedTextListener - { - /** - * Called to indicate an avaliable timed text - * - * @param mp the QCMediaPlayer associated with this - * callback - * @param text the Qtimed text sample which contains the text - * needed to be displayed and the display format. - * {@hide} - */ - public void onQCTimedText(QCMediaPlayer mp, QCTimedText text); - } - - /** - * Register a callback to be invoked when a Qtimed text is available - * for display. - * - * @param listener the callback that will be run - * {@hide} - */ - public void setOnQCTimedTextListener(OnQCTimedTextListener listener) - { - Log.d(TAG, "setOnQCTimedTextListener"); - - mOnQCTimedTextListener = listener; - TurnOnOffTimedTextListener(); - } - private OnQCTimedTextListener mOnQCTimedTextListener; - - /** - * Register a callback to be invoked when the media source is ready - * for playback. - * - * @param listener the callback that will be run - */ - public void setOnPreparedListener(OnPreparedListener listener) - { - mQCOnPreparedListener = listener; - Log.d(TAG, "setOnPreparedListener"); - } - private OnPreparedListener mQCOnPreparedListener; - - /** - * Interface definition for a callback to be invoked when the media - * source is ready for MPD attribute retrieval - */ - public interface OnMPDAttributeListener - { - /** - * Key to identify type of MPD attributes - */ - public static final int ATTRIBUTES_TYPE_MPD = 8002; - /** - * Key to be used to retrieve complete MPD. - */ - public static final int ATTRIBUTES_WHOLE_MPD = 8003; - /** - * Key to Get MPD attributes - */ - public static final int INVOKE_ID_GET_ATTRIBUTES_TYPE_MPD = 8010; - - /** - * Key to Set MPD attributes - */ - public static final int INVOKE_ID_SET_ATTRIBUTES_TYPE_MPD = 8011; - - /** - * Called when attributes are available. - * - * @param attributekey the key identifying the type of attributes available - * @param value the value for the attribute - * @param mp the MediaPlayer to which MPD attribute is applicable - * - */ - public void onMPDAttribute(int attributekey, String value, QCMediaPlayer mp); - } - - /** - * Register a callback to be invoked when MPD attributes are avaialble - * - * @param listener the callback that will be run - */ - public void setOnMPDAttributeListener(OnMPDAttributeListener listener) - { - mOnMPDAttributeListener = listener; - } - - private OnMPDAttributeListener mOnMPDAttributeListener; - - /** - * Process the parameter indicated by key. - * @param key the key idicated the parameter to be processed - * @param value the value for the parameter identified by key - * @return true if successful in processing the parameter else returns false - * @see OnMPDAttributeListener the interface for valid keys to be used - * - */ - public boolean processMPDAttribute(int key, String value) - { - boolean retval = false; - if(key == OnMPDAttributeListener.ATTRIBUTES_TYPE_MPD) - { - key = OnMPDAttributeListener.INVOKE_ID_SET_ATTRIBUTES_TYPE_MPD; - } - return QCsetStringParameter(key, value); - } - public String QCGetParameter(int key) - { - if(key == OnMPDAttributeListener.ATTRIBUTES_TYPE_MPD) - { - key = OnMPDAttributeListener.INVOKE_ID_GET_ATTRIBUTES_TYPE_MPD; - } - - return QCgetStringParameter(key); - } - public Parcel QCPeriodicParameter(int key) - { - if(key == mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_PERIODIC) - { - return QCgetParcelParameter(key); - } - return null; - } - public boolean QCSetParameter(int key, int value) - { - Log.d(TAG, "QCMediaPlayer : QCSetParameter"); - return QCsetParameter(key, value); - } - - /** - * Interface definition for a callback to be invoked when the media - * source is ready for QOE data retrieval. - */ - public interface OnQOEEventListener - { - /** - * Key to identify type of QOE Event - */ - public static final int ATTRIBUTES_QOE_EVENT_REG = 8004; - public static final int ATTRIBUTES_QOE_EVENT_PLAY = 8005; - public static final int ATTRIBUTES_QOE_EVENT_STOP = 8006; - public static final int ATTRIBUTES_QOE_EVENT_SWITCH = 8007; - public static final int ATTRIBUTES_QOE_EVENT_PERIODIC = 8008; - - /** - * Called when attributes are available. - * - * @param attributekey the key identifying the type of attributes available - * @param value the value for the attribute - * @param mp the MediaPlayer to which QOE event is - * applicable - * - */ - public void onQOEAttribute(int key, Parcel value,QCMediaPlayer mp); - } - /** - * Register a callback to be invoked when QOE event happens - * @param listener the callback that will be run - */ - public void setOnQOEEventListener(OnQOEEventListener listener) - { - mOnQOEEventListener = listener; - } - - private OnQOEEventListener mOnQOEEventListener; - /* Do not change these values without updating their counterparts - * in include/media/mediaplayer.h! - */ - private static final int MEDIA_NOP = 0; // interface test message - private static final int MEDIA_PREPARED = 1; - private static final int MEDIA_PLAYBACK_COMPLETE = 2; - private static final int MEDIA_BUFFERING_UPDATE = 3; - private static final int MEDIA_SEEK_COMPLETE = 4; - private static final int MEDIA_SET_VIDEO_SIZE = 5; - private static final int MEDIA_TIMED_TEXT = 99; - private static final int MEDIA_ERROR = 100; - private static final int MEDIA_INFO = 200; - private static final int MEDIA_QOE = 300; - -/* This sequence needs to be same as defined in NuPlayer.h*/ - private static final int QOEPlay = 1; - private static final int QOEStop = 2; - private static final int QOESwitch = 3; - private static final int QOEPeriodic =4; - - /*enum QOEEvent{ - QOE, - QOEPlay, - QOEStop, - QOESwitch, - QOEPeriodic - };*/ - - /** - * Key to query reposition range. Value needs to be same as defined in DashPlayer.h - */ - public static final int KEY_DASH_REPOSITION_RANGE = 9000; - - /** - * Keys for dash playback modes. Value needs to be same as defined in DashPlayer.h - */ - public static final int KEY_DASH_SEEK_EVENT = 7001; - public static final int KEY_DASH_PAUSE_EVENT = 7002; - public static final int KEY_DASH_RESUME_EVENT = 7003; - - public static final int KEY_QCTIMEDTEXT_LISTENER = 6000; - - enum MediaPlayerState { - PLAYER_IDLE, - PLAYER_INITIALIZED - }; - - public MediaPlayerState ePlayerState; - - private class QCMediaEventHandler extends Handler - { - private QCMediaPlayer mQCMediaPlayer; - - public QCMediaEventHandler(QCMediaPlayer mp, Looper looper){ - super(looper); - Log.d(TAG, "QCMediaEventHandler calling mp.mEventHandler.sendMessage()m"); - mQCMediaPlayer = mp; - } - - public void handleMessage(Message msg) - { - Log.d(TAG, "QCMediaPlayer::QCMediaEventHandler::handleMessage"); - switch(msg.what) - { - case MEDIA_PREPARED: - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_PREPARED calling callOnMPDAttributeListener"); - callOnMPDAttributeListener(); - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_PREPARED calling callOnPreparedListener"); - callOnPreparedListener(); - return; - - case MEDIA_TIMED_TEXT: - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_TIMED_TEXT"); - if(mOnQCTimedTextListener != null) - { - if (msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - QCTimedText text = new QCTimedText(parcel); - callQCTimedTextListener(text); - } - } - return; - - case MEDIA_QOE: - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_QOE Received " + msg.arg2); - if(mOnQOEEventListener != null) - { - if (msg.obj instanceof Parcel) - { - int key = 0; - Parcel parcel = (Parcel)msg.obj; - if(msg.arg2 == /*(int)QOEEvent.*/QOEPlay) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_PLAY; - }else if(msg.arg2 == /*(int)QOEEvent.*/QOEPeriodic) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_PERIODIC; - }else if(msg.arg2 == /*(int)QOEEvent.*/QOESwitch) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_SWITCH; - }else if(msg.arg2 == /*(int)QOEEvent.*/QOEStop) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_STOP; - } - callOnQOEEventListener(key,parcel); - } - } - return; - - default: - Log.d(TAG, "Unknown message type " + msg.what); - return; - } - } - } - - /** - * Called from native code when an interesting event happens. This method - * just uses the EventHandler system to post the event back to the main app thread. - * We use a weak reference to the original QCMediaPlayer object so that the native - * code is safe from the object disappearing from underneath it. (This is - * the cookie passed to native_setup().) - */ - private static void QCMediaPlayerNativeEventHandler(Object mediaplayer_ref, - int what, int arg1, int arg2, Object obj) - { - Log.d(TAG, "QCMediaPlayerNativeEventHandler"); - QCMediaPlayer mp = (QCMediaPlayer)((WeakReference)mediaplayer_ref).get(); - if (mp == null) - { - Log.d(TAG, "QCMediaPlayerNativeEventHandler mp == null"); - return; - } - if (mp.mEventHandler != null) - { - Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); - Log.d(TAG, "QCMediaPlayerNativeEventHandler calling mp.mEventHandler.sendMessage()"); - mp.mEventHandler.sendMessage(m); - } - } - - private String QCgetStringParameter(int key) - { - if(!VALID_GET_PARAM_KEYS.contains(new Integer(key))) { - Log.d(TAG, "QCgetStringParameter Unsupported key "+key+" Return null"); - return null; - } - - Parcel request = newRequest(); - Parcel reply = Parcel.obtain(); - reply.setDataPosition(0); - request.writeInt(key); - invoke(request, reply); - String ret = reply.readString(); - request.recycle(); - reply.recycle(); - return ret; - } - - public boolean QCsetStringParameter(int key, String value) { - boolean retval = false; - Parcel request = newRequest(); - Parcel reply = Parcel.obtain(); - request.writeInt(key); - request.writeString(value); - invoke(request, reply); - retval = reply.readInt() > 0 ? true : false; - request.recycle(); - reply.recycle(); - return retval; - } - - public boolean QCsetParameter(int key, int value) { - boolean retval = false; - Parcel request = newRequest(); - Parcel reply = Parcel.obtain(); - request.writeInt(key); - request.writeInt(value); - invoke(request, reply); - retval = reply.readInt() > 0 ? true : false; - request.recycle(); - reply.recycle(); - return retval; - } - - public Parcel QCgetParcelParameter(int key) { - - if(!VALID_GET_PARAM_KEYS.contains(new Integer(key))) { - Log.d(TAG, "QCgetParcelParameter Unsupported key "+key+" Return null"); - return null; - } - Parcel request = newRequest(); - Parcel reply = Parcel.obtain(); - request.writeInt(key); - invoke(request, reply); - request.recycle(); - return reply; - } -} diff --git a/QCMediaPlayer/com/qualcomm/qcmedia/QCMediaPlayer.java b/QCMediaPlayer/com/qualcomm/qcmedia/QCMediaPlayer.java deleted file mode 100644 index 432abf3e..00000000 --- a/QCMediaPlayer/com/qualcomm/qcmedia/QCMediaPlayer.java +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. - * - * File: QCMediaPlayer.java - * Description: Snapdragon SDK for Android support class. - * Provides access to QC-provided MediaPlayer APIs and interfaces - - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * Copyright (C) 2006 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.qualcomm.qcmedia; - -import android.media.MediaPlayer; -import android.util.Log; -import android.media.TimedText; -import java.lang.ref.WeakReference; -import java.io.*; -import com.qualcomm.qcmedia.QCTimedText; -import android.os.Handler; -import android.os.Looper; -import android.os.Message; -import android.os.Parcel; - -/** -* QCMediaPlayer extends MediaPlayer from package android.media and provides -* extended APIs and interfaces to get and set MPD attributes for DASH protocol -* in compatible Snapdragon builds. -*{@hide} -*/ - -public class QCMediaPlayer extends MediaPlayer -{ - private final static String TAG = "QCMediaPlayer"; - private QCMediaEventHandler mEventHandler; - - public QCMediaPlayer() - { - super(); - Looper looper; - if ((looper = Looper.myLooper()) != null) - { - mEventHandler = new QCMediaEventHandler(this, looper); - } - else if ((looper = Looper.getMainLooper()) != null) - { - mEventHandler = new QCMediaEventHandler(this, looper); - } - else - { - mEventHandler = null; - } - Log.d(TAG, "QCMediaPlayer::QCMediaPlayer"); - } - - private void callOnPreparedListener() - { - Log.d(TAG, "callOnPreparedListener"); - if (mQCOnPreparedListener != null) - mQCOnPreparedListener.onPrepared(this); - } - - private void callOnMPDAttributeListener() - { - Log.d(TAG, "callOnMPDAttributeListener"); - String mpdAttributes = getStringParameter(OnMPDAttributeListener.ATTRIBUTES_TYPE_MPD); - if (mOnMPDAttributeListener != null) - mOnMPDAttributeListener.onMPDAttribute(OnMPDAttributeListener.ATTRIBUTES_TYPE_MPD, mpdAttributes, this); - } - private void callQCTimedTextListener(QCTimedText text) - { - if(mOnQCTimedTextListener != null) - { - mOnQCTimedTextListener.onQCTimedText(this, text); - } - } - private void callOnQOEEventListener(int key,Parcel parcel) - { - Log.d(TAG, "callOnQOEEventListener"); - if (mOnQOEEventListener != null) - { - mOnQOEEventListener.onQOEAttribute(key,parcel,this); - } - } - - /** - * Additional propreitary interface definition of a callback to be invoked - * when a Qtimed text is available for display. - * {@hide} - */ - public interface OnQCTimedTextListener - { - /** - * Called to indicate an avaliable timed text - * - * @param mp the QCMediaPlayer associated with this - * callback - * @param text the Qtimed text sample which contains the text - * needed to be displayed and the display format. - * {@hide} - */ - public void onQCTimedText(QCMediaPlayer mp, QCTimedText text); - } - - /** - * Register a callback to be invoked when a Qtimed text is available - * for display. - * - * @param listener the callback that will be run - * {@hide} - */ - public void setOnQCTimedTextListener(OnQCTimedTextListener listener) - { - mOnQCTimedTextListener = listener; - } - private OnQCTimedTextListener mOnQCTimedTextListener; - - /** - * Register a callback to be invoked when the media source is ready - * for playback. - * - * @param listener the callback that will be run - */ - public void setOnPreparedListener(OnPreparedListener listener) - { - mQCOnPreparedListener = listener; - Log.d(TAG, "QCMediaPlayer::setOnPreparedListener"); - } - private OnPreparedListener mQCOnPreparedListener; - - /** - * Interface definition for a callback to be invoked when the media - * source is ready for MPD attribute retrieval - */ - public interface OnMPDAttributeListener - { - /** - * Key to identify type of MPD attributes - */ - public static final int ATTRIBUTES_TYPE_MPD = 8002; - /** - * Key to be used to retrieve complete MPD. - */ - public static final int ATTRIBUTES_WHOLE_MPD = 8003; - /** - * Called when attributes are available. - * - * @param attributekey the key identifying the type of attributes available - * @param value the value for the attribute - * @param mp the MediaPlayer to which MPD attribute is applicable - * - */ - public void onMPDAttribute(int attributekey, String value, QCMediaPlayer mp); - } - - /** - * Register a callback to be invoked when MPD attributes are avaialble - * - * @param listener the callback that will be run - */ - public void setOnMPDAttributeListener(OnMPDAttributeListener listener) - { - mOnMPDAttributeListener = listener; - } - - private OnMPDAttributeListener mOnMPDAttributeListener; - - /** - * Process the parameter indicated by key. - * @param key the key idicated the parameter to be processed - * @param value the value for the parameter identified by key - * @return true if successful in processing the parameter else returns false - * @see OnMPDAttributeListener the interface for valid keys to be used - * - */ - public boolean processMPDAttribute(int key, String value) - { - return setParameter(key, value); - } - public String QCGetParameter(int key) - { - return getStringParameter(key); - } - public Parcel QCPeriodicParameter(int key) - { - if(key == mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_PERIODIC) - { - Log.d(TAG, "QCMediaPlayer : QCGetParameter(int key , Parcel& data)"); - return getParcelParameter(key); - } - return null; - } - public boolean QCSetParameter(int key, int value) - { - Log.d(TAG, "QCMediaPlayer : QCSetParameter"); - return setParameter(key, value); - } - /** - * Interface definition for a callback to be invoked when the media - * source is ready for QOE data retrieval. - */ - public interface OnQOEEventListener - { - /** - * Key to identify type of QOE Event - */ - public static final int ATTRIBUTES_QOE_EVENT_REG = 8004; - public static final int ATTRIBUTES_QOE_EVENT_PLAY = 8005; - public static final int ATTRIBUTES_QOE_EVENT_STOP = 8006; - public static final int ATTRIBUTES_QOE_EVENT_SWITCH = 8007; - public static final int ATTRIBUTES_QOE_EVENT_PERIODIC = 8008; - - /** - * Called when attributes are available. - * - * @param attributekey the key identifying the type of attributes available - * @param value the value for the attribute - * @param mp the MediaPlayer to which QOE event is - * applicable - * - */ - public void onQOEAttribute(int key, Parcel value,QCMediaPlayer mp); - } - /** - * Register a callback to be invoked when QOE event happens - * @param listener the callback that will be run - */ - public void setOnQOEEventListener(OnQOEEventListener listener) - { - mOnQOEEventListener = listener; - } - - private OnQOEEventListener mOnQOEEventListener; - /* Do not change these values without updating their counterparts - * in include/media/mediaplayer.h! - */ - private static final int MEDIA_NOP = 0; // interface test message - private static final int MEDIA_PREPARED = 1; - private static final int MEDIA_PLAYBACK_COMPLETE = 2; - private static final int MEDIA_BUFFERING_UPDATE = 3; - private static final int MEDIA_SEEK_COMPLETE = 4; - private static final int MEDIA_SET_VIDEO_SIZE = 5; - private static final int MEDIA_TIMED_TEXT = 99; - private static final int MEDIA_ERROR = 100; - private static final int MEDIA_INFO = 200; - private static final int MEDIA_QOE = 300; - -/* This sequence needs to be same as defined in NuPlayer.h*/ - private static final int QOEPlay = 1; - private static final int QOEStop = 2; - private static final int QOESwitch = 3; - private static final int QOEPeriodic =4; - - /*enum QOEEvent{ - QOE, - QOEPlay, - QOEStop, - QOESwitch, - QOEPeriodic - };*/ - - private class QCMediaEventHandler extends Handler - { - private QCMediaPlayer mQCMediaPlayer; - - public QCMediaEventHandler(QCMediaPlayer mp, Looper looper){ - super(looper); - Log.d(TAG, "QCMediaEventHandler calling mp.mEventHandler.sendMessage()m"); - mQCMediaPlayer = mp; - } - - public void handleMessage(Message msg) - { - Log.d(TAG, "QCMediaPlayer::QCMediaEventHandler::handleMessage"); - switch(msg.what) - { - case MEDIA_PREPARED: - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_PREPARED calling callOnMPDAttributeListener"); - callOnMPDAttributeListener(); - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_PREPARED calling callOnPreparedListener"); - callOnPreparedListener(); - return; - - case MEDIA_TIMED_TEXT: - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_TIMED_TEXT"); - if(mOnQCTimedTextListener != null) - { - if (msg.obj instanceof Parcel) { - Parcel parcel = (Parcel)msg.obj; - QCTimedText text = new QCTimedText(parcel); - callQCTimedTextListener(text); - } - } - return; - - case MEDIA_QOE: - Log.d(TAG, "QCMediaEventHandler::handleMessage::MEDIA_QOE Received " + msg.arg2); - if(mOnQOEEventListener != null) - { - if (msg.obj instanceof Parcel) - { - int key = 0; - Parcel parcel = (Parcel)msg.obj; - if(msg.arg2 == /*(int)QOEEvent.*/QOEPlay) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_PLAY; - }else if(msg.arg2 == /*(int)QOEEvent.*/QOEPeriodic) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_PERIODIC; - }else if(msg.arg2 == /*(int)QOEEvent.*/QOESwitch) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_SWITCH; - }else if(msg.arg2 == /*(int)QOEEvent.*/QOEStop) - { - key = mOnQOEEventListener.ATTRIBUTES_QOE_EVENT_STOP; - } - callOnQOEEventListener(key,parcel); - } - } - return; - - default: - Log.d(TAG, "Unknown message type " + msg.what); - return; - } - } - } - - /** - * Called from native code when an interesting event happens. This method - * just uses the EventHandler system to post the event back to the main app thread. - * We use a weak reference to the original QCMediaPlayer object so that the native - * code is safe from the object disappearing from underneath it. (This is - * the cookie passed to native_setup().) - */ - private static void QCMediaPlayerNativeEventHandler(Object mediaplayer_ref, - int what, int arg1, int arg2, Object obj) - { - Log.d(TAG, "QCMediaPlayerNativeEventHandler"); - QCMediaPlayer mp = (QCMediaPlayer)((WeakReference)mediaplayer_ref).get(); - if (mp == null) - { - Log.d(TAG, "QCMediaPlayerNativeEventHandler mp == null"); - return; - } - if (mp.mEventHandler != null) - { - Message m = mp.mEventHandler.obtainMessage(what, arg1, arg2, obj); - Log.d(TAG, "QCMediaPlayerNativeEventHandler calling mp.mEventHandler.sendMessage()"); - mp.mEventHandler.sendMessage(m); - } - } -} diff --git a/QCMediaPlayer/com/qualcomm/qcmedia/QCTimedText.java b/QCMediaPlayer/com/qualcomm/qcmedia/QCTimedText.java deleted file mode 100644 index ef092c21..00000000 --- a/QCMediaPlayer/com/qualcomm/qcmedia/QCTimedText.java +++ /dev/null @@ -1,801 +0,0 @@ -/* - * Copyright (c) 2012-2013, The Linux Foundation. All rights reserved. - * - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - */ - -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -/* - * File: QCTimedText.java - * Description: Snapdragon SDK for Android support class. - * Provides access to QC-provided TimedText APIs and interfaces - * - */ -package com.qualcomm.qcmedia; - -import android.media.MediaPlayer; -import android.util.Log; - -import android.os.Parcel; -import android.util.Log; -import java.util.HashMap; -import java.util.Set; -import java.util.List; -import java.util.ArrayList; - -/** - * Class to hold the timed text's metadata. - * It holds local settings(per sample) as well as global settings. - * - * {@hide} - */ -public class QCTimedText -{ - private static final int FIRST_PUBLIC_KEY = 1; - - // These keys must be in sync with the keys in TextDescription.h - public static final int KEY_DISPLAY_FLAGS = 1; // int - public static final int KEY_STYLE_FLAGS = 2; // int - public static final int KEY_BACKGROUND_COLOR_RGBA = 3; // int - public static final int KEY_HIGHLIGHT_COLOR_RGBA = 4; // int - public static final int KEY_SCROLL_DELAY = 5; // int - public static final int KEY_WRAP_TEXT = 6; // int - public static final int KEY_START_TIME = 7; // int - public static final int KEY_STRUCT_BLINKING_TEXT_LIST = 8; // List<CharPos> - public static final int KEY_STRUCT_FONT_LIST = 9; // List<Font> - public static final int KEY_STRUCT_HIGHLIGHT_LIST = 10; // List<CharPos> - public static final int KEY_STRUCT_HYPER_TEXT_LIST = 11; // List<HyperText> - public static final int KEY_STRUCT_KARAOKE_LIST = 12; // List<Karaoke> - public static final int KEY_STRUCT_STYLE_LIST = 13; // List<Style> - public static final int KEY_STRUCT_TEXT_POS = 14; // TextPos - public static final int KEY_STRUCT_JUSTIFICATION = 15; // Justification - public static final int KEY_STRUCT_TEXT = 16; // Text - public static final int KEY_HEIGHT = 17; - public static final int KEY_WIDTH = 18; - public static final int KEY_DURATION = 19; - public static final int KEY_START_OFFSET = 20; - public static final int KEY_SUBS_ATOM = 21; - //The type of text - SMPTE, CEA, WebVTT, SRT or Unknown - public static final int KEY_TEXT_FORMAT = 22; - - private static final int LAST_PUBLIC_KEY = 22; - - private static final int FIRST_PRIVATE_KEY = 101; - - // The following keys are used between QCTimedText.java and - // TextDescription.cpp in order to parce the Parcel. - private static final int KEY_GLOBAL_SETTING = 101; - private static final int KEY_LOCAL_SETTING = 102; - private static final int KEY_START_CHAR = 103; - private static final int KEY_END_CHAR = 104; - private static final int KEY_FONT_ID = 105; - private static final int KEY_FONT_SIZE = 106; - private static final int KEY_TEXT_COLOR_RGBA = 107; - private static final int KEY_TEXT_EOS = 108; - private static final int KEY_TEXT_FLAG_TYPE = 109; - private static final int KEY_TEXT_DISCONTINUITY = 110; - private static final int LAST_PRIVATE_KEY = 110; - - - private static final String TAG = "QCTimedText"; - - private final HashMap<Integer, Object> mKeyObjectMap = - new HashMap<Integer, Object>(); - - private int mDisplayFlags = -1; - private int mBackgroundColorRGBA = -1; - private int mHighlightColorRGBA = -1; - private int mScrollDelay = -1; - private int mWrapText = -1; - - private List<CharPos> mBlinkingPosList = null; - private List<CharPos> mHighlightPosList = null; - private List<Karaoke> mKaraokeList = null; - private List<Font> mFontList = null; - private List<Style> mStyleList = null; - private List<HyperText> mHyperTextList = null; - - private TextPos mTextPos; - private Justification mJustification; - private Text mTextStruct; - private SubsAtom mSubsAtomStruct; - - /** - * Helper class to hold the text length and text content of - * one text sample. The member variables in this class are - * read-only. - */ - public class Text { - - public static final int TIMED_TEXT_FLAG_FRAME = 0; // int - public static final int TIMED_TEXT_FLAG_CODEC_CONFIG = 1; // int - public static final int TIMED_TEXT_FLAG_EOS = 2; // int - - /** - * The byte-count of this text sample - */ - public int textLen; - /** - * The flags associated with frame - */ - public int flags; - /** - * The discontinuity in samples - */ - public boolean discontinuity = false; - - /** - * The text sample - */ - public byte[] text; - - public Text() { } - } - - /** - * Helper class to hold the start char offset and end char offset - * for Blinking Text or Highlight Text. endChar is the end offset - * of the text (startChar + number of characters to be highlighted - * or blinked). The member variables in this class are read-only. - */ - public class CharPos { - /** - * The offset of the start character - */ - public int startChar = -1; - - /** - * The offset of the end character - */ - public int endChar = -1; - - public CharPos() { } - } - - /** - * Helper class to hold the box position to display the text sample. - * The member variables in this class are read-only. - */ - public class TextPos { - /** - * The top position of the text - */ - public int top = -1; - - /** - * The left position of the text - */ - public int left = -1; - - /** - * The bottom position of the text - */ - public int bottom = -1; - - /** - * The right position of the text - */ - public int right = -1; - - public TextPos() { } - } - - /** - * Helper class to hold the justification for text display in the text box. - * The member variables in this class are read-only. - */ - public class Justification { - /** - * horizontalJustification 0: left, 1: centered, -1: right - */ - public int horizontalJustification = -1; - - /** - * verticalJustification 0: top, 1: centered, -1: bottom - */ - public int verticalJustification = -1; - - public Justification() { } - } - - /** - * Helper class to hold the style information to display the text. - * The member variables in this class are read-only. - */ - public class Style { - /** - * The offset of the start character which applys this style - */ - public int startChar = -1; - - /** - * The offset of the end character which applys this style - */ - public int endChar = -1; - - /** - * ID of the font. This ID will be used to choose the font - * to be used from the font list. - */ - public int fontID = -1; - - /** - * True if the characters should be bold - */ - public boolean isBold = false; - - /** - * True if the characters should be italic - */ - public boolean isItalic = false; - - /** - * True if the characters should be underlined - */ - public boolean isUnderlined = false; - - /** - * The size of the font - */ - public int fontSize = -1; - - /** - * To specify the RGBA color: 8 bits each of red, green, blue, - * and an alpha(transparency) value - */ - public int colorRGBA = -1; - - public Style() { } - } - - /** - * Helper class to hold the font ID and name. - * The member variables in this class are read-only. - */ - public class Font { - /** - * The font ID - */ - public int ID = -1; - - /** - * The font name - */ - public String name; - - public Font() { } - } - - /** - * Helper class to hold the karaoke information. - * The member variables in this class are read-only. - */ - public class Karaoke { - /** - * The start time (in milliseconds) to highlight the characters - * specified by startChar and endChar. - */ - public int startTimeMs = -1; - - /** - * The end time (in milliseconds) to highlight the characters - * specified by startChar and endChar. - */ - public int endTimeMs = -1; - - /** - * The offset of the start character to be highlighted - */ - public int startChar = -1; - - /** - * The offset of the end character to be highlighted - */ - public int endChar = -1; - - public Karaoke() { } - } - - /** - * Helper class to hold the hyper text information. - * The member variables in this class are read-only. - */ - public class HyperText { - /** - * The offset of the start character - */ - public int startChar = -1; - - /** - * The offset of the end character - */ - public int endChar = -1; - - /** - * The linked-to URL - */ - public String URL; - - /** - * The "alt" string for user display - */ - public String altString; - - public HyperText() { } - } - - /* Subs Atom*/ - public class SubsAtom { - /** - * The byte-count of this subs - */ - public int subsAtomLen; - - /** - * The subs data - */ - public byte[] subsAtomData; - - public SubsAtom () { } - } - - /** - * @param obj the byte array which contains the timed text. - * @throws IllegalArgumentExcept if parseParcel() fails. - * {@hide} - */ - public QCTimedText(Parcel mParcel) { - - if (!parseParcel(mParcel)) { - mKeyObjectMap.clear(); - throw new IllegalArgumentException("parseParcel() fails"); - } - } - - /** - * Go over all the records, collecting metadata keys and fields in the - * Parcel. These are stored in mKeyObjectMap for application to retrieve. - * @return false if an error occurred during parsing. Otherwise, true. - */ - private boolean parseParcel(Parcel mParcel) { - mParcel.setDataPosition(0); - if (mParcel.dataAvail() == 0) { - Log.e(TAG, "Invalid mParcel.dataAvail()"); - return false; - } - - int type = mParcel.readInt(); - - if (type == KEY_LOCAL_SETTING) { - - mTextStruct = new Text(); - - //PARSE TIMEDTEXT SAMPLE TYPE - type = mParcel.readInt(); - if (type != KEY_TEXT_FORMAT) { - Log.e(TAG, "Invalid KEY_TEXT_FORMAT key"); - return false; - } - - String format = mParcel.readString(); - mKeyObjectMap.put(type, format); - - //PARSE TIMEDTEXT SAMPLE FLAGS - type = mParcel.readInt(); - if (type != KEY_TEXT_FLAG_TYPE) { - Log.e(TAG, "Invalid KEY_TEXT_FLAG_TYPE key"); - return false; - } - - type = mParcel.readInt(); - if (type == Text.TIMED_TEXT_FLAG_EOS) - { - mTextStruct.flags = type; - mTextStruct.textLen = 0; //Zero length buffer in case of EOS - mKeyObjectMap.put(KEY_STRUCT_TEXT, mTextStruct); - mKeyObjectMap.put(KEY_START_TIME, 0); - mKeyObjectMap.put(KEY_HEIGHT, 0); - mKeyObjectMap.put(KEY_WIDTH, 0); - mKeyObjectMap.put(KEY_DURATION, 0); - mKeyObjectMap.put(KEY_START_OFFSET, 0); - - return true; - } - - if(type != Text.TIMED_TEXT_FLAG_FRAME && type != Text.TIMED_TEXT_FLAG_CODEC_CONFIG) { - Log.e(TAG, "Invalid TIMED_TEXT_FLAG_FRAME key"); - return false; - } - mTextStruct.flags = type; - - type = mParcel.readInt(); - if(type == KEY_TEXT_DISCONTINUITY) { - mTextStruct.discontinuity = true; - type = mParcel.readInt(); - } - - //PARSE TIMEDTEXT SAMPLE TEXT DATA - if (type != KEY_STRUCT_TEXT) { - Log.e(TAG, "Invalid KEY_STRUCT_TEXT key"); - return false; - } - - mTextStruct.textLen = mParcel.readInt(); - mTextStruct.text = mParcel.createByteArray(); - - mKeyObjectMap.put(type, mTextStruct); - - //PARSE TIMEDTEXT SAMPLE PROPERTIES - type = mParcel.readInt(); - if (type != KEY_START_TIME) { - Log.e(TAG, "Invalid KEY_START_TIME key"); - return false; - } - int mStartTimeMs = mParcel.readInt(); - mKeyObjectMap.put(type, mStartTimeMs); - - } else if (type != KEY_GLOBAL_SETTING) { - Log.e(TAG, "Invalid timed text key found: " + type); - return false; - } - - while (mParcel.dataAvail() > 0) { - int key = mParcel.readInt(); - if (!isValidKey(key)) { - Log.w(TAG, "Invalid timed text key found: " + key); - return false; - } - - Object object = null; - - switch (key) { - case KEY_HEIGHT: { - int mHeight = mParcel.readInt(); - Log.e(TAG, "mHeight: " + mHeight); - mKeyObjectMap.put(key, mHeight); - break; - } - - case KEY_WIDTH: { - int mWidth = mParcel.readInt(); - Log.e(TAG, "mWidth: " + mWidth); - mKeyObjectMap.put(key, mWidth); - break; - } - - case KEY_DURATION: { - int mDuration = mParcel.readInt(); - Log.e(TAG, "mDuration: " + mDuration); - mKeyObjectMap.put(key, mDuration); - break; - } - - case KEY_START_OFFSET: { - int mStartOffset = mParcel.readInt(); - Log.e(TAG, "mStartOffset: " + mStartOffset); - mKeyObjectMap.put(key, mStartOffset); - break; - } - - //Parse SubsAtom - case KEY_SUBS_ATOM: { - mSubsAtomStruct = new SubsAtom(); - mSubsAtomStruct.subsAtomLen = mParcel.readInt(); - mSubsAtomStruct.subsAtomData = mParcel.createByteArray(); - mKeyObjectMap.put(key, mSubsAtomStruct); - break; - } - - case KEY_STRUCT_STYLE_LIST: { - readStyle(mParcel); - object = mStyleList; - break; - } - case KEY_STRUCT_FONT_LIST: { - readFont(mParcel); - object = mFontList; - break; - } - case KEY_STRUCT_HIGHLIGHT_LIST: { - readHighlight(mParcel); - object = mHighlightPosList; - break; - } - case KEY_STRUCT_KARAOKE_LIST: { - readKaraoke(mParcel); - object = mKaraokeList; - break; - } - case KEY_STRUCT_HYPER_TEXT_LIST: { - readHyperText(mParcel); - object = mHyperTextList; - - break; - } - case KEY_STRUCT_BLINKING_TEXT_LIST: { - readBlinkingText(mParcel); - object = mBlinkingPosList; - - break; - } - case KEY_WRAP_TEXT: { - mWrapText = mParcel.readInt(); - object = mWrapText; - break; - } - case KEY_HIGHLIGHT_COLOR_RGBA: { - mHighlightColorRGBA = mParcel.readInt(); - object = mHighlightColorRGBA; - break; - } - case KEY_DISPLAY_FLAGS: { - mDisplayFlags = mParcel.readInt(); - object = mDisplayFlags; - break; - } - case KEY_STRUCT_JUSTIFICATION: { - mJustification = new Justification(); - - mJustification.horizontalJustification = mParcel.readInt(); - mJustification.verticalJustification = mParcel.readInt(); - - object = mJustification; - break; - } - case KEY_BACKGROUND_COLOR_RGBA: { - mBackgroundColorRGBA = mParcel.readInt(); - object = mBackgroundColorRGBA; - break; - } - case KEY_STRUCT_TEXT_POS: { - mTextPos = new TextPos(); - - mTextPos.top = mParcel.readInt(); - mTextPos.left = mParcel.readInt(); - mTextPos.bottom = mParcel.readInt(); - mTextPos.right = mParcel.readInt(); - - object = mTextPos; - break; - } - case KEY_SCROLL_DELAY: { - mScrollDelay = mParcel.readInt(); - object = mScrollDelay; - break; - } - default: { - break; - } - } - - if (object != null) { - if (mKeyObjectMap.containsKey(key)) { - mKeyObjectMap.remove(key); - } - mKeyObjectMap.put(key, object); - } - } - - return true; - } - - /** - * To parse and store the Style list. - */ - private void readStyle(Parcel mParcel) { - Style style = new Style(); - boolean endOfStyle = false; - - while (!endOfStyle && (mParcel.dataAvail() > 0)) { - int key = mParcel.readInt(); - switch (key) { - case KEY_START_CHAR: { - style.startChar = mParcel.readInt(); - break; - } - case KEY_END_CHAR: { - style.endChar = mParcel.readInt(); - break; - } - case KEY_FONT_ID: { - style.fontID = mParcel.readInt(); - break; - } - case KEY_STYLE_FLAGS: { - int flags = mParcel.readInt(); - // In the absence of any bits set in flags, the text - // is plain. Otherwise, 1: bold, 2: italic, 4: underline - style.isBold = ((flags % 2) == 1); - style.isItalic = ((flags % 4) >= 2); - style.isUnderlined = ((flags / 4) == 1); - break; - } - case KEY_FONT_SIZE: { - style.fontSize = mParcel.readInt(); - break; - } - case KEY_TEXT_COLOR_RGBA: { - style.colorRGBA = mParcel.readInt(); - break; - } - default: { - // End of the Style parsing. Reset the data position back - // to the position before the last mParcel.readInt() call. - mParcel.setDataPosition(mParcel.dataPosition() - 4); - endOfStyle = true; - break; - } - } - } - - if (mStyleList == null) { - mStyleList = new ArrayList<Style>(); - } - mStyleList.add(style); - } - - /** - * To parse and store the Font list - */ - private void readFont(Parcel mParcel) { - int entryCount = mParcel.readInt(); - - for (int i = 0; i < entryCount; i++) { - Font font = new Font(); - - font.ID = mParcel.readInt(); - int nameLen = mParcel.readInt(); - - byte[] text = mParcel.createByteArray(); - font.name = new String(text, 0, nameLen); - - if (mFontList == null) { - mFontList = new ArrayList<Font>(); - } - mFontList.add(font); - } - } - - /** - * To parse and store the Highlight list - */ - private void readHighlight(Parcel mParcel) { - CharPos pos = new CharPos(); - - pos.startChar = mParcel.readInt(); - pos.endChar = mParcel.readInt(); - - if (mHighlightPosList == null) { - mHighlightPosList = new ArrayList<CharPos>(); - } - mHighlightPosList.add(pos); - } - - /** - * To parse and store the Karaoke list - */ - private void readKaraoke(Parcel mParcel) { - int entryCount = mParcel.readInt(); - - for (int i = 0; i < entryCount; i++) { - Karaoke kara = new Karaoke(); - - kara.startTimeMs = mParcel.readInt(); - kara.endTimeMs = mParcel.readInt(); - kara.startChar = mParcel.readInt(); - kara.endChar = mParcel.readInt(); - - if (mKaraokeList == null) { - mKaraokeList = new ArrayList<Karaoke>(); - } - mKaraokeList.add(kara); - } - } - - /** - * To parse and store HyperText list - */ - private void readHyperText(Parcel mParcel) { - HyperText hyperText = new HyperText(); - - hyperText.startChar = mParcel.readInt(); - hyperText.endChar = mParcel.readInt(); - - int len = mParcel.readInt(); - byte[] url = mParcel.createByteArray(); - hyperText.URL = new String(url, 0, len); - - len = mParcel.readInt(); - byte[] alt = mParcel.createByteArray(); - hyperText.altString = new String(alt, 0, len); - - if (mHyperTextList == null) { - mHyperTextList = new ArrayList<HyperText>(); - } - mHyperTextList.add(hyperText); - } - - /** - * To parse and store blinking text list - */ - private void readBlinkingText(Parcel mParcel) { - CharPos blinkingPos = new CharPos(); - - blinkingPos.startChar = mParcel.readInt(); - blinkingPos.endChar = mParcel.readInt(); - - if (mBlinkingPosList == null) { - mBlinkingPosList = new ArrayList<CharPos>(); - } - mBlinkingPosList.add(blinkingPos); - } - - /** - * To check whether the given key is valid. - * @param key the key to be checked. - * @return true if the key is a valid one. Otherwise, false. - */ - public boolean isValidKey(final int key) { - if (!((key >= FIRST_PUBLIC_KEY) && (key <= LAST_PUBLIC_KEY)) - && !((key >= FIRST_PRIVATE_KEY) && (key <= LAST_PRIVATE_KEY))) { - return false; - } - return true; - } - - /** - * To check whether the given key is contained in this QCTimedText object. - * @param key the key to be checked. - * @return true if the key is contained in this QCTimedText object. - * Otherwise, false. - */ - public boolean containsKey(final int key) { - if (isValidKey(key) && mKeyObjectMap.containsKey(key)) { - return true; - } - return false; - } - /** - * @return a set of the keys contained in this QCTimedText object. - */ - public Set keySet() { - return mKeyObjectMap.keySet(); - } - - /** - * To retrieve the object associated with the key. Caller must make sure - * the key is present using the containsKey method otherwise a - * RuntimeException will occur. - * @param key the key used to retrieve the object. - * @return an object. The object could be an instanceof Integer, List, or - * any of the helper classes such as TextPos, Justification, and Text. - */ - public Object getObject(final int key) { - if (containsKey(key)) { - return mKeyObjectMap.get(key); - } - return null; -/* - //!Warning : Not Sure if to throw an exception or return null , return null is good option - else { - throw new IllegalArgumentException("Invalid key: " + key); - } -*/ - } -} diff --git a/dashplayer/Android.mk b/dashplayer/Android.mk deleted file mode 100644 index acf9a7a7..00000000 --- a/dashplayer/Android.mk +++ /dev/null @@ -1,60 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -# --------------------------------------------------------------------------------- -# Common definitons -# --------------------------------------------------------------------------------- -LOCAL_SRC_FILES:= \ - DashPlayer.cpp \ - DashPlayerDriver.cpp \ - DashPlayerRenderer.cpp \ - DashPlayerStats.cpp \ - DashPlayerDecoder.cpp \ - DashPacketSource.cpp \ - DashFactory.cpp - -LOCAL_SHARED_LIBRARIES := \ - libbinder \ - libcamera_client \ - libcutils \ - libdl \ - libgui \ - libmedia \ - libstagefright \ - libstagefright_foundation \ - libstagefright_omx \ - libutils \ - libui \ - -LOCAL_C_INCLUDES := \ - $(TOP)/frameworks/av/media/libstagefright/timedtext \ - $(TOP)/frameworks/native/include/media/hardware \ - $(TOP)/frameworks/native/include/media/openmax \ - $(TOP)/frameworks/av/media/libstagefright/httplive \ - $(TOP)/frameworks/av/media/libmediaplayerservice/nuplayer \ - $(TOP)/frameworks/av/media/libmediaplayerservice \ - $(TOP)/frameworks/av/media/libstagefright/include \ - $(TOP)/frameworks/av/media/libstagefright/mpeg2ts \ - $(TOP)/frameworks/av/media/libstagefright/rtsp \ - $(TOP)/$(call project-path-for,qcom-media)/mm-core/inc \ - $(TOP)/$(call project-path-for,qcom-display)/libgralloc \ - $(LOCAL_PATH)/../QCMediaPlayer/native \ - $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr/include - -LOCAL_ADDITIONAL_DEPENDENCIES := $(TARGET_OUT_INTERMEDIATES)/KERNEL_OBJ/usr - -ifeq ($(PLATFORM_SDK_VERSION), 18) - LOCAL_CFLAGS += -DANDROID_JB_MR2 -endif - - -LOCAL_MODULE:= libdashplayer - -LOCAL_MODULE_TAGS := eng - -ifeq ($(TARGET_ENABLE_QC_AV_ENHANCEMENTS), true) -ifndef TARGET_DISABLE_DASH - include $(BUILD_SHARED_LIBRARY) -endif -endif - diff --git a/dashplayer/DashCodec.cpp b/dashplayer/DashCodec.cpp deleted file mode 100644 index c8db281d..00000000 --- a/dashplayer/DashCodec.cpp +++ /dev/null @@ -1,4671 +0,0 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "DashCodec" - -#include "DashCodec.h" -#include "QCMediaDefs.h" - -#include <binder/MemoryDealer.h> - -#include <media/stagefright/foundation/hexdump.h> -#include <media/stagefright/foundation/ABuffer.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AMessage.h> - -#include <media/stagefright/MediaCodecList.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/NativeWindowWrapper.h> -#include <media/stagefright/OMXClient.h> -#include <media/stagefright/OMXCodec.h> - -#include <media/hardware/HardwareAPI.h> -#include <OMX_QCOMExtns.h> -#include <OMX_Component.h> -#include <cutils/properties.h> -#include "avc_utils.h" - -#ifdef BFAMILY_TARGET /* Venus macros and dynamic mode support present only for B-family targets.*/ -#include <media/msm_media_info.h> -#endif - -//Smmoth streaming settings -//Max resolution 1080p -#define MAX_WIDTH 1920 -#define MAX_HEIGHT 1080 - -//Min resolution QVGA -#define MIN_WIDTH 480 -#define MIN_HEIGHT 320 - -#define MAX_SUPPORTED_BUF_SZ (((MAX_WIDTH * MAX_HEIGHT)*3/2)/2) -// Alignment Macro -#define ALIGN(x, to_align) ((((unsigned) x) + (to_align - 1)) & ~(to_align - 1)) -#define SZ_4K 0x1000 - -namespace android { - -template<class T> -static void InitOMXParams(T *params) { - params->nSize = sizeof(T); - params->nVersion.s.nVersionMajor = 1; - params->nVersion.s.nVersionMinor = 0; - params->nVersion.s.nRevision = 0; - params->nVersion.s.nStep = 0; -} - -struct CodecObserver : public BnOMXObserver { - CodecObserver() {} - - void setNotificationMessage(const sp<AMessage> &msg) { - mNotify = msg; - } - - // from IOMXObserver - virtual void onMessage(const omx_message &omx_msg) { - sp<AMessage> msg = mNotify->dup(); - - msg->setInt32("type", omx_msg.type); - msg->setInt32("node", omx_msg.node); - - switch (omx_msg.type) { - case omx_message::EVENT: - { - msg->setInt32("event", omx_msg.u.event_data.event); - msg->setInt32("data1", omx_msg.u.event_data.data1); - msg->setInt32("data2", omx_msg.u.event_data.data2); - break; - } - - case omx_message::EMPTY_BUFFER_DONE: - { - msg->setInt32("buffer", omx_msg.u.buffer_data.buffer); - break; - } - - case omx_message::FILL_BUFFER_DONE: - { - msg->setInt32( - "buffer", omx_msg.u.extended_buffer_data.buffer); - msg->setInt32( - "range_offset", - omx_msg.u.extended_buffer_data.range_offset); - msg->setInt32( - "range_length", - omx_msg.u.extended_buffer_data.range_length); - msg->setInt32( - "flags", - omx_msg.u.extended_buffer_data.flags); - msg->setInt64( - "timestamp", - omx_msg.u.extended_buffer_data.timestamp); - //msg->setPointer( - // "platform_private", - // omx_msg.u.extended_buffer_data.platform_private); - //msg->setPointer( - // "data_ptr", - // omx_msg.u.extended_buffer_data.data_ptr); - break; - } - - default: - TRESPASS(); - break; - } - - msg->post(); - } - -protected: - virtual ~CodecObserver() {} - -private: - sp<AMessage> mNotify; - - DISALLOW_EVIL_CONSTRUCTORS(CodecObserver); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::BaseState : public AState { - BaseState(DashCodec *codec, const sp<AState> &parentState = NULL); - -protected: - enum PortMode { - KEEP_BUFFERS, - RESUBMIT_BUFFERS, - FREE_BUFFERS, - }; - - DashCodec *mCodec; - - virtual PortMode getPortMode(OMX_U32 portIndex); - - virtual bool onMessageReceived(const sp<AMessage> &msg); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - - virtual void onOutputBufferDrained(const sp<AMessage> &msg); - virtual void onInputBufferFilled(const sp<AMessage> &msg); - - void postFillThisBuffer(BufferInfo *info); - -private: - bool onOMXMessage(const sp<AMessage> &msg); - - bool onOMXEmptyBufferDone(IOMX::buffer_id bufferID); - - bool onOMXFillBufferDone( - IOMX::buffer_id bufferID, - size_t rangeOffset, size_t rangeLength, - OMX_U32 flags, - int64_t timeUs, - void *platformPrivate, - void *dataPtr); - - void getMoreInputDataIfPossible(); - - DISALLOW_EVIL_CONSTRUCTORS(BaseState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::UninitializedState : public DashCodec::BaseState { - UninitializedState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - -private: - void onSetup(const sp<AMessage> &msg); - bool onAllocateComponent(const sp<AMessage> &msg); - - DISALLOW_EVIL_CONSTRUCTORS(UninitializedState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::LoadedState : public DashCodec::BaseState { - LoadedState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - -private: - friend struct DashCodec::UninitializedState; - - bool onConfigureComponent(const sp<AMessage> &msg); - void onStart(); - void onShutdown(bool keepComponentAllocated); - - DISALLOW_EVIL_CONSTRUCTORS(LoadedState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::LoadedToIdleState : public DashCodec::BaseState { - LoadedToIdleState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - virtual void stateEntered(); - -private: - status_t allocateBuffers(); - - DISALLOW_EVIL_CONSTRUCTORS(LoadedToIdleState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::IdleToExecutingState : public DashCodec::BaseState { - IdleToExecutingState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - virtual void stateEntered(); - -private: - DISALLOW_EVIL_CONSTRUCTORS(IdleToExecutingState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::ExecutingState : public DashCodec::BaseState { - ExecutingState(DashCodec *codec); - - void submitRegularOutputBuffers(); - void submitOutputMetaBuffers(); - void submitOutputBuffers(); - - // Submit output buffers to the decoder, submit input buffers to client - // to fill with data. - void resume(); - - // Returns true iff input and output buffers are in play. - bool active() const { return mActive; } - -protected: - virtual PortMode getPortMode(OMX_U32 portIndex); - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - -private: - bool mActive; - - DISALLOW_EVIL_CONSTRUCTORS(ExecutingState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::OutputPortSettingsChangedState : public DashCodec::BaseState { - OutputPortSettingsChangedState(DashCodec *codec); - -protected: - virtual PortMode getPortMode(OMX_U32 portIndex); - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void enableOutputPort(OMX_U32 data1, OMX_U32 data2); - virtual void stateEntered(); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - -private: - DISALLOW_EVIL_CONSTRUCTORS(OutputPortSettingsChangedState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::ExecutingToIdleState : public DashCodec::BaseState { - ExecutingToIdleState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - - virtual void onOutputBufferDrained(const sp<AMessage> &msg); - virtual void onInputBufferFilled(const sp<AMessage> &msg); - -private: - void changeStateIfWeOwnAllBuffers(); - - bool mComponentNowIdle; - - DISALLOW_EVIL_CONSTRUCTORS(ExecutingToIdleState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::IdleToLoadedState : public DashCodec::BaseState { - IdleToLoadedState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - -private: - DISALLOW_EVIL_CONSTRUCTORS(IdleToLoadedState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::FlushingState : public DashCodec::BaseState { - FlushingState(DashCodec *codec); - -protected: - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - - virtual void onOutputBufferDrained(const sp<AMessage> &msg); - virtual void onInputBufferFilled(const sp<AMessage> &msg); - -private: - bool mFlushComplete[2]; - - void changeStateIfWeOwnAllBuffers(); - - DISALLOW_EVIL_CONSTRUCTORS(FlushingState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -struct DashCodec::FlushingOutputState : public DashCodec::BaseState { - FlushingOutputState(DashCodec *codec); - -protected: - virtual PortMode getPortMode(OMX_U32 portIndex); - virtual bool onMessageReceived(const sp<AMessage> &msg); - virtual void stateEntered(); - - virtual bool onOMXEvent(OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2); - - virtual void onOutputBufferDrained(const sp<AMessage> &msg); - virtual void onInputBufferFilled(const sp<AMessage> &msg); - -private: - bool mFlushComplete; - - void changeStateIfWeOwnAllBuffers(); - - DISALLOW_EVIL_CONSTRUCTORS(FlushingOutputState); -}; - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::DashCodec() - : mQuirks(0), - mNode(NULL), - mSentFormat(false), - mPostFormat(false), - mIsEncoder(false), - mShutdownInProgress(false), - mEncoderDelay(0), - mEncoderPadding(0), - mChannelMaskPresent(false), - mChannelMask(0), - mDequeueCounter(0), - mStoreMetaDataInOutputBuffers(false), - mMetaDataBuffersToSubmit(0), - mCurrentWidth(0), - mCurrentHeight(0), - mAdaptivePlayback(false) { - mUninitializedState = new UninitializedState(this); - mLoadedState = new LoadedState(this); - mLoadedToIdleState = new LoadedToIdleState(this); - mIdleToExecutingState = new IdleToExecutingState(this); - mExecutingState = new ExecutingState(this); - - mOutputPortSettingsChangedState = - new OutputPortSettingsChangedState(this); - - mExecutingToIdleState = new ExecutingToIdleState(this); - mIdleToLoadedState = new IdleToLoadedState(this); - mFlushingState = new FlushingState(this); - mFlushingOutputState = new FlushingOutputState(this); - - mPortEOS[kPortIndexInput] = mPortEOS[kPortIndexOutput] = false; - mInputEOSResult = OK; - - changeState(mUninitializedState); -} - -DashCodec::~DashCodec() { - clearCachedFormats(); -} - -void DashCodec::setNotificationMessage(const sp<AMessage> &msg) { - mNotify = msg; -} - -void DashCodec::initiateSetup(const sp<AMessage> &msg) { - msg->setWhat(kWhatSetup); - msg->setTarget(id()); - msg->post(); -} - -void DashCodec::initiateAllocateComponent(const sp<AMessage> &msg) { - msg->setWhat(kWhatAllocateComponent); - msg->setTarget(id()); - msg->post(); -} - -void DashCodec::initiateConfigureComponent(const sp<AMessage> &msg) { - msg->setWhat(kWhatConfigureComponent); - msg->setTarget(id()); - msg->post(); -} - -void DashCodec::initiateStart() { - (new AMessage(kWhatStart, id()))->post(); -} - -void DashCodec::signalFlush() { - ALOGV("[%s] signalFlush", mComponentName.c_str()); - (new AMessage(kWhatFlush, id()))->post(); -} - -void DashCodec::signalResume() { - (new AMessage(kWhatResume, id()))->post(); -} - -void DashCodec::initiateShutdown(bool keepComponentAllocated) { - sp<AMessage> msg = new AMessage(kWhatShutdown, id()); - msg->setInt32("keepComponentAllocated", keepComponentAllocated); - msg->post(); -} - -void DashCodec::signalRequestIDRFrame() { - (new AMessage(kWhatRequestIDRFrame, id()))->post(); -} - -status_t DashCodec::allocateBuffersOnPort(OMX_U32 portIndex) { - CHECK(portIndex == kPortIndexInput || portIndex == kPortIndexOutput); - - CHECK(mDealer[portIndex] == NULL); - CHECK(mBuffers[portIndex].isEmpty()); - - status_t err; - if (mNativeWindow != NULL && portIndex == kPortIndexOutput) { - if (mStoreMetaDataInOutputBuffers) { - err = allocateOutputMetaDataBuffers(); - } else { - err = allocateOutputBuffersFromNativeWindow(); - } - } else { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err == OK) { - ALOGV("[%s] Allocating %lu buffers of size %lu on %s port", - mComponentName.c_str(), - def.nBufferCountActual, def.nBufferSize, - portIndex == kPortIndexInput ? "input" : "output"); - - size_t totalSize = def.nBufferCountActual * def.nBufferSize; - mDealer[portIndex] = new MemoryDealer(totalSize, "DashCodec"); - - for (OMX_U32 i = 0; i < def.nBufferCountActual; ++i) { - sp<IMemory> mem = mDealer[portIndex]->allocate(def.nBufferSize); - CHECK(mem.get() != NULL); - - BufferInfo info; - info.mStatus = BufferInfo::OWNED_BY_US; - - uint32_t requiresAllocateBufferBit = - (portIndex == kPortIndexInput) - ? OMXCodec::kRequiresAllocateBufferOnInputPorts - : OMXCodec::kRequiresAllocateBufferOnOutputPorts; - - if (portIndex == kPortIndexInput && (mFlags & kFlagIsSecure)) { - mem.clear(); - - void *ptr; - err = mOMX->allocateBuffer( - mNode, portIndex, def.nBufferSize, &info.mBufferID, - &ptr); - - info.mData = new ABuffer(ptr, def.nBufferSize); - } else if (mQuirks & requiresAllocateBufferBit) { - err = mOMX->allocateBufferWithBackup( - mNode, portIndex, mem, &info.mBufferID); - } else { - err = mOMX->useBuffer(mNode, portIndex, mem, &info.mBufferID); - } - - if (mem != NULL) { - info.mData = new ABuffer(mem->pointer(), def.nBufferSize); - } - - mBuffers[portIndex].push(info); - } - } - } - - if (err != OK) { - return err; - } - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatBuffersAllocated); - - notify->setInt32("portIndex", portIndex); - - sp<PortDescription> desc = new PortDescription; - - for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) { - const BufferInfo &info = mBuffers[portIndex][i]; - - desc->addBuffer(info.mBufferID, info.mData); - } - - notify->setObject("portDesc", desc); - notify->post(); - - return OK; -} - -status_t DashCodec::configureOutputBuffersFromNativeWindow( -OMX_U32 *bufferCount, OMX_U32 *bufferSize, - OMX_U32 *minUndequeuedBuffers) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - err = native_window_set_buffers_dimensions( - mNativeWindow.get(), - def.format.video.nFrameWidth, - def.format.video.nFrameHeight); - - if (err != NO_ERROR) { - ALOGE("native_window_set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_set_buffers_format( - mNativeWindow.get(), - def.format.video.eColorFormat); - - if (err != NO_ERROR) { - ALOGE("native_window_set_buffers_format failed: %s (%d)", - strerror(-err), -err); - return err; - } - - // Set up the native window. - OMX_U32 usage = 0; - err = mOMX->getGraphicBufferUsage(mNode, kPortIndexOutput, &usage); - if (err != 0) { - ALOGW("querying usage flags from OMX IL component failed: %d", err); - // XXX: Currently this error is logged, but not fatal. - usage = 0; - } - - if (mFlags & kFlagIsSecure || mFlags & kFlagIsSecureOPOnly) { - usage |= GRALLOC_USAGE_PROTECTED; - } - - // Make sure to check whether either Stagefright or the video decoder - // requested protected buffers. - if (usage & GRALLOC_USAGE_PROTECTED) { - // Verify that the ANativeWindow sends images directly to - // SurfaceFlinger. - int queuesToNativeWindow = 0; - err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_QUEUES_TO_WINDOW_COMPOSER, - &queuesToNativeWindow); - if (err != 0) { - ALOGE("error authenticating native window: %d", err); - return err; - } - if (queuesToNativeWindow != 1) { - ALOGE("native window could not be authenticated"); - return PERMISSION_DENIED; - } - } - - err = native_window_set_usage( - mNativeWindow.get(), - usage | GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_EXTERNAL_DISP); - - if (err != 0) { - ALOGE("native_window_set_usage failed: %s (%d)", strerror(-err), -err); - return err; - } - - *minUndequeuedBuffers = 0; - err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - (int *)minUndequeuedBuffers); - - if (err != 0) { - ALOGE("NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", - strerror(-err), -err); - return err; - } - - //add an extra buffer to display queue to get around dequeue+wait - //blocking too long (more than 1 Vsync) in case BufferQeuue is in - //sync-mode and advertizes only 1 buffer - (*minUndequeuedBuffers)++; - ALOGI("NOTE: Overriding minUndequeuedBuffers to %lu",*minUndequeuedBuffers); - - // XXX: Is this the right logic to use? It's not clear to me what the OMX - // buffer counts refer to - how do they account for the renderer holding on - // to buffers? - if (def.nBufferCountActual < def.nBufferCountMin + *minUndequeuedBuffers) { - OMX_U32 newBufferCount = def.nBufferCountMin + *minUndequeuedBuffers; - def.nBufferCountActual = newBufferCount; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - ALOGE("[%s] setting nBufferCountActual to %lu failed: %d", - mComponentName.c_str(), newBufferCount, err); - return err; - } - } - - - err = native_window_set_buffer_count( - mNativeWindow.get(), def.nBufferCountActual); - - if (err != 0) { - ALOGE("native_window_set_buffer_count failed: %s (%d)", strerror(-err), - -err); - return err; - } - - *bufferCount = def.nBufferCountActual; - *bufferSize = def.nBufferSize; - return err; -} - -status_t DashCodec::allocateOutputBuffersFromNativeWindow() { - OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers; - status_t err = configureOutputBuffersFromNativeWindow( - &bufferCount, &bufferSize, &minUndequeuedBuffers); - if (err != 0) - return err; - - ALOGV("[%s] Allocating %lu buffers from a native window of size %lu on " - "output port", - mComponentName.c_str(), bufferCount, bufferSize); - - // Dequeue buffers and send them to OMX - for (OMX_U32 i = 0; i < bufferCount; i++) { - ANativeWindowBuffer *buf; - err = native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf); - if (err != 0) { - ALOGE("dequeueBuffer failed: %s (%d)", strerror(-err), -err); - break; - } - - sp<GraphicBuffer> graphicBuffer(new GraphicBuffer(buf, false)); - BufferInfo info; - info.mStatus = BufferInfo::OWNED_BY_US; - info.mData = new ABuffer(NULL /* data */, bufferSize /* capacity */); - info.mGraphicBuffer = graphicBuffer; - mBuffers[kPortIndexOutput].push(info); - - IOMX::buffer_id bufferId; - err = mOMX->useGraphicBuffer(mNode, kPortIndexOutput, graphicBuffer, - &bufferId); - if (err != 0) { - ALOGE("registering GraphicBuffer %lu with OMX IL component failed: " - "%d", i, err); - break; - } - - mBuffers[kPortIndexOutput].editItemAt(i).mBufferID = bufferId; - - ALOGV("[%s] Registered graphic buffer with ID %p (pointer = %p)", - mComponentName.c_str(), - bufferId, graphicBuffer.get()); - } - - OMX_U32 cancelStart; - OMX_U32 cancelEnd; - - if (err != 0) { - // If an error occurred while dequeuing we need to cancel any buffers - // that were dequeued. - cancelStart = 0; - cancelEnd = mBuffers[kPortIndexOutput].size(); - } else { - // Return the required minimum undequeued buffers to the native window. - cancelStart = bufferCount - minUndequeuedBuffers; - cancelEnd = bufferCount; - } - - for (OMX_U32 i = cancelStart; i < cancelEnd; i++) { - BufferInfo *info = &mBuffers[kPortIndexOutput].editItemAt(i); - cancelBufferToNativeWindow(info); - } - - return err; -} - -status_t DashCodec::allocateOutputMetaDataBuffers() { - OMX_U32 bufferCount, bufferSize, minUndequeuedBuffers; - status_t err = configureOutputBuffersFromNativeWindow( - &bufferCount, &bufferSize, &minUndequeuedBuffers); - if (err != 0) - return err; - - ALOGV("[%s] Allocating %lu meta buffers on output port", - mComponentName.c_str(), bufferCount); - - size_t totalSize = bufferCount * 8; - mDealer[kPortIndexOutput] = new MemoryDealer(totalSize, "DashCodec"); - - // Dequeue buffers and send them to OMX - for (OMX_U32 i = 0; i < bufferCount; i++) { - BufferInfo info; - info.mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; - info.mGraphicBuffer = NULL; - info.mDequeuedAt = mDequeueCounter; - - sp<IMemory> mem = mDealer[kPortIndexOutput]->allocate( - sizeof(struct VideoDecoderOutputMetaData)); - CHECK(mem.get() != NULL); - info.mData = new ABuffer(mem->pointer(), mem->size()); - - // we use useBuffer for metadata regardless of quirks - err = mOMX->useBuffer( - mNode, kPortIndexOutput, mem, &info.mBufferID); - - mBuffers[kPortIndexOutput].push(info); - - ALOGV("[%s] allocated meta buffer with ID %p (pointer = %p)", - mComponentName.c_str(), info.mBufferID, mem->pointer()); - } - - mMetaDataBuffersToSubmit = bufferCount - minUndequeuedBuffers; - return err; -} - -status_t DashCodec::submitOutputMetaDataBuffer() { - CHECK(mStoreMetaDataInOutputBuffers); - if (mMetaDataBuffersToSubmit == 0) - return OK; - - BufferInfo *info = dequeueBufferFromNativeWindow(); - if (info == NULL) - return ERROR_IO; - - ALOGV("[%s] submitting output meta buffer ID %p for graphic buffer %p", - mComponentName.c_str(), info->mBufferID, info->mGraphicBuffer.get()); - - --mMetaDataBuffersToSubmit; - CHECK_EQ(mOMX->fillBuffer(mNode, info->mBufferID), - (status_t)OK); - - info->mStatus = BufferInfo::OWNED_BY_COMPONENT; - return OK; -} - -status_t DashCodec::cancelBufferToNativeWindow(BufferInfo *info) { - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); - - ALOGV("[%s] Calling cancelBuffer on buffer %p", - mComponentName.c_str(), info->mBufferID); - - int err = mNativeWindow->cancelBuffer( - mNativeWindow.get(), info->mGraphicBuffer.get(), -1); - - CHECK_EQ(err, 0); - - info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; - - return OK; -} - -DashCodec::BufferInfo *DashCodec::dequeueBufferFromNativeWindow() { - ANativeWindowBuffer *buf; - int fenceFd = -1; - CHECK(mNativeWindow.get() != NULL); - if (native_window_dequeue_buffer_and_wait(mNativeWindow.get(), &buf) != 0) { - ALOGE("dequeueBuffer failed."); - return NULL; - } - - BufferInfo *oldest = NULL; - for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) { - BufferInfo *info = - &mBuffers[kPortIndexOutput].editItemAt(i); - - if (info->mGraphicBuffer != NULL && - info->mGraphicBuffer->handle == buf->handle) { - CHECK_EQ((int)info->mStatus, - (int)BufferInfo::OWNED_BY_NATIVE_WINDOW); - - info->mStatus = BufferInfo::OWNED_BY_US; - - return info; - } - - if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW && - (oldest == NULL || - // avoid potential issues from counter rolling over - mDequeueCounter - info->mDequeuedAt > - mDequeueCounter - oldest->mDequeuedAt)) { - oldest = info; - } - } - - if (oldest) { - CHECK(mStoreMetaDataInOutputBuffers); - - // discard buffer in LRU info and replace with new buffer - oldest->mGraphicBuffer = new GraphicBuffer(buf, false); - oldest->mStatus = BufferInfo::OWNED_BY_US; - - mOMX->updateGraphicBufferInMeta( - mNode, kPortIndexOutput, oldest->mGraphicBuffer, - oldest->mBufferID); - VideoDecoderOutputMetaData *metaData = - reinterpret_cast<VideoDecoderOutputMetaData *>( - oldest->mData->base()); - CHECK_EQ(metaData->eType, kMetadataBufferTypeGrallocSource); - - ALOGV("replaced oldest buffer #%u with age %u (%p/%p stored in %p)", - oldest - &mBuffers[kPortIndexOutput][0], - mDequeueCounter - oldest->mDequeuedAt, - metaData->pHandle, - oldest->mGraphicBuffer->handle, oldest->mData->base()); - - return oldest; - } - - TRESPASS(); - - return NULL; -} - -status_t DashCodec::freeBuffersOnPort(OMX_U32 portIndex) { - for (size_t i = mBuffers[portIndex].size(); i-- > 0;) { - CHECK_EQ((status_t)OK, freeBuffer(portIndex, i)); - } - - mDealer[portIndex].clear(); - - return OK; -} - -status_t DashCodec::freeOutputBuffersNotOwnedByComponent() { - for (size_t i = mBuffers[kPortIndexOutput].size(); i-- > 0;) { - BufferInfo *info = - &mBuffers[kPortIndexOutput].editItemAt(i); - - // At this time some buffers may still be with the component - // or being drained. - if (info->mStatus != BufferInfo::OWNED_BY_COMPONENT && - info->mStatus != BufferInfo::OWNED_BY_DOWNSTREAM) { - CHECK_EQ((status_t)OK, freeBuffer(kPortIndexOutput, i)); - } - } - - return OK; -} - -status_t DashCodec::freeBuffer(OMX_U32 portIndex, size_t i) { - BufferInfo *info = &mBuffers[portIndex].editItemAt(i); - - CHECK(info->mStatus == BufferInfo::OWNED_BY_US - || info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW); - - if (portIndex == kPortIndexOutput && mNativeWindow != NULL - && info->mStatus == BufferInfo::OWNED_BY_US) { - CHECK_EQ((status_t)OK, cancelBufferToNativeWindow(info)); - } - - CHECK_EQ(mOMX->freeBuffer( - mNode, portIndex, info->mBufferID), - (status_t)OK); - - mBuffers[portIndex].removeAt(i); - - return OK; -} - -DashCodec::BufferInfo *DashCodec::findBufferByID( - uint32_t portIndex, IOMX::buffer_id bufferID, - ssize_t *index) { - for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) { - BufferInfo *info = &mBuffers[portIndex].editItemAt(i); - - if (info->mBufferID == bufferID) { - if (index != NULL) { - *index = i; - } - return info; - } - } - - TRESPASS(); - - return NULL; -} - -status_t DashCodec::setComponentRole( - bool isEncoder, const char *mime) { - struct MimeToRole { - const char *mime; - const char *decoderRole; - const char *encoderRole; - }; - - static const MimeToRole kMimeToRole[] = { - { MEDIA_MIMETYPE_AUDIO_MPEG, - "audio_decoder.mp3", "audio_encoder.mp3" }, - { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_I, - "audio_decoder.mp1", "audio_encoder.mp1" }, - { MEDIA_MIMETYPE_AUDIO_MPEG_LAYER_II, - "audio_decoder.mp2", "audio_encoder.mp2" }, - { MEDIA_MIMETYPE_AUDIO_AMR_NB, - "audio_decoder.amrnb", "audio_encoder.amrnb" }, - { MEDIA_MIMETYPE_AUDIO_AMR_WB, - "audio_decoder.amrwb", "audio_encoder.amrwb" }, - // commenting out AMR_WM_PLUS for bringing up dash on MR2 - /* { MEDIA_MIMETYPE_AUDIO_AMR_WB_PLUS, - "audio_decoder.amrwbplus", "audio_encoder.amrwbplus" }, */ - { MEDIA_MIMETYPE_AUDIO_AAC, - "audio_decoder.aac", "audio_encoder.aac" }, - { MEDIA_MIMETYPE_AUDIO_VORBIS, - "audio_decoder.vorbis", "audio_encoder.vorbis" }, - { MEDIA_MIMETYPE_AUDIO_G711_MLAW, - "audio_decoder.g711mlaw", "audio_encoder.g711mlaw" }, - { MEDIA_MIMETYPE_AUDIO_G711_ALAW, - "audio_decoder.g711alaw", "audio_encoder.g711alaw" }, - { MEDIA_MIMETYPE_VIDEO_AVC, - "video_decoder.avc", "video_encoder.avc" }, - { MEDIA_MIMETYPE_VIDEO_MPEG4, - "video_decoder.mpeg4", "video_encoder.mpeg4" }, - { MEDIA_MIMETYPE_VIDEO_H263, - "video_decoder.h263", "video_encoder.h263" }, - { MEDIA_MIMETYPE_AUDIO_RAW, - "audio_decoder.raw", "audio_encoder.raw" }, - { MEDIA_MIMETYPE_AUDIO_FLAC, - "audio_decoder.flac", "audio_encoder.flac" }, - { MEDIA_MIMETYPE_VIDEO_HEVC, - "video_decoder.hevc", "video_encoder.hevc" }, - }; - - static const size_t kNumMimeToRole = - sizeof(kMimeToRole) / sizeof(kMimeToRole[0]); - - size_t i; - for (i = 0; i < kNumMimeToRole; ++i) { - if (!strcasecmp(mime, kMimeToRole[i].mime)) { - break; - } - } - - if (i == kNumMimeToRole) { - return ERROR_UNSUPPORTED; - } - - const char *role = - isEncoder ? kMimeToRole[i].encoderRole - : kMimeToRole[i].decoderRole; - - if (role != NULL) { - OMX_PARAM_COMPONENTROLETYPE roleParams; - InitOMXParams(&roleParams); - - strncpy((char *)roleParams.cRole, - role, OMX_MAX_STRINGNAME_SIZE - 1); - - roleParams.cRole[OMX_MAX_STRINGNAME_SIZE - 1] = '\0'; - - status_t err = mOMX->setParameter( - mNode, OMX_IndexParamStandardComponentRole, - &roleParams, sizeof(roleParams)); - - if (err != OK) { - ALOGW("[%s] Failed to set standard component role '%s'.", - mComponentName.c_str(), role); - - return err; - } - } - - return OK; -} - -status_t DashCodec::configureCodec( - const char *mime, const sp<AMessage> &msg) { - int32_t encoder; - if (!msg->findInt32("encoder", &encoder)) { - encoder = false; - } - - mIsEncoder = encoder; - - status_t err = setComponentRole(encoder /* isEncoder */, mime); - - if (err != OK) { - return err; - } - - int32_t bitRate = 0; - // FLAC encoder doesn't need a bitrate, other encoders do - if (encoder && strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC) - && !msg->findInt32("bitrate", &bitRate)) { - return INVALID_OPERATION; - } - - int32_t storeMeta; - if (encoder - && msg->findInt32("store-metadata-in-buffers", &storeMeta) - && storeMeta != 0) { - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexInput, OMX_TRUE); - - if (err != OK) { - ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d", - mComponentName.c_str(), err); - - return err; - } - else - { - ALOGE("[%s] storeMetaDataInBuffers succedded", mComponentName.c_str()); - } - } - - int32_t prependSPSPPS; - if (encoder - && msg->findInt32("prepend-sps-pps-to-idr-frames", &prependSPSPPS) - && prependSPSPPS != 0) { - OMX_INDEXTYPE index; - err = mOMX->getExtensionIndex( - mNode, - "OMX.google.android.index.prependSPSPPSToIDRFrames", - &index); - - if (err == OK) { - PrependSPSPPSToIDRFramesParams params; - InitOMXParams(¶ms); - params.bEnable = OMX_TRUE; - - err = mOMX->setParameter( - mNode, index, ¶ms, sizeof(params)); - } - - if (err != OK) { - ALOGE("Encoder could not be configured to emit SPS/PPS before " - "IDR frames. (err %d)", err); - - return err; - } - } - - // Always try to enable dynamic output buffers on native surface - int32_t video = !strncasecmp(mime, "video/", 6); - sp<RefBase> obj; - int32_t haveNativeWindow = msg->findObject("native-window", &obj) && - obj != NULL; - mStoreMetaDataInOutputBuffers = false; - - bool mEnableDynamicBuffering = true; - char property_value[PROPERTY_VALUE_MAX]; - property_value[0] = '\0'; - property_get("persist.dash.dbm.enable", property_value, "1"); - if(*property_value) - { - mEnableDynamicBuffering = atoi(property_value) > 0 ? true: false; - ALOGE("DynamicBuffering is set to [%d]", mEnableDynamicBuffering); - } - // Do not use Dynamic Buffer or Adaptive playback for HEVC, the HEVC decoder hybrid solution - // that is being used doesnt support these mode , so just use port reconfig mode - if (!encoder && video && haveNativeWindow && (strcmp(mime,"video/hevc")!= 0)) { - - if (mEnableDynamicBuffering) - { - ALOGE("Enabling Dynamic Buffering Mode"); - err = mOMX->storeMetaDataInBuffers(mNode, kPortIndexOutput, OMX_TRUE); - } - else - { - ALOGE("Disabling Dynamic Buffering Mode Thru SetProp"); - err = INVALID_OPERATION; - } - if (err != OK) { - - ALOGE("[%s] storeMetaDataInBuffers failed w/ err %d", - mComponentName.c_str(), err); - - // if adaptive playback has been requested, try JB fallback - // NOTE: THIS FALLBACK MECHANISM WILL BE REMOVED DUE TO ITS - // LARGE MEMORY REQUIREMENT - - // we will not do adaptive playback on software accessed - // surfaces as they never had to respond to changes in the - // crop window, and we don't trust that they will be able to. - int usageBits = 0; - - sp<NativeWindowWrapper> windowWrapper( - static_cast<NativeWindowWrapper *>(obj.get())); - sp<ANativeWindow> nativeWindow = windowWrapper->getNativeWindow(); - - if (nativeWindow->query( - nativeWindow.get(), - NATIVE_WINDOW_CONSUMER_USAGE_BITS, - &usageBits) != OK) { - } else { - mAdaptivePlayback = - (usageBits & - (GRALLOC_USAGE_SW_READ_MASK | - GRALLOC_USAGE_SW_WRITE_MASK)) == 0; - } - int32_t maxWidth = MAX_WIDTH; - int32_t maxHeight = MAX_HEIGHT; - if (mAdaptivePlayback) { - ALOGV("[%s] prepareForAdaptivePlayback(%ldx%ld)", - mComponentName.c_str(), maxWidth, maxHeight); - - err = mOMX->prepareForAdaptivePlayback( - mNode, kPortIndexOutput, OMX_TRUE, maxWidth, maxHeight); - if (err != OK) - { - ALOGE("[%s] prepareForAdaptivePlayback failed w/ err %d", - mComponentName.c_str(), err); - } - else - { - ALOGV("[%s] prepareForAdaptivePlayback : Success", - mComponentName.c_str(), err); - } - } - // allow failure - err = OK; - } else { - ALOGV("[%s] storeMetaDataInBuffers succeeded", mComponentName.c_str()); - mStoreMetaDataInOutputBuffers = true; - } - - int32_t push; - if (msg->findInt32("push-blank-buffers-on-shutdown", &push) - && push != 0) { - mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; - } - } - if (!strncasecmp(mime, "video/", 6)) { - if (encoder) { - err = setupVideoEncoder(mime, msg); - } else { - int32_t width, height; - if (!msg->findInt32("width", &width) - || !msg->findInt32("height", &height)) { - err = INVALID_OPERATION; - } else { - //override height & width with max for smooth streaming - if (mAdaptivePlayback) { - width = MAX_WIDTH; - height = MAX_HEIGHT; - } - ALOGE("[%s] setupVideoDecoder with width %d, height %d", - mComponentName.c_str(),width,height); - err = setupVideoDecoder(mime, width, height); - - QOMX_VIDEO_CUSTOM_BUFFERSIZE sCustomBufferSize; - sCustomBufferSize.nPortIndex = kPortIndexInput; - sCustomBufferSize.nBufferSize = (OMX_U32)(MAX_SUPPORTED_BUF_SZ); - - ALOGV("[%s] Set Inputbuffers size %lu Input Port [Before Alignment]", - mComponentName.c_str(), - sCustomBufferSize.nBufferSize); - //Doing 4K alignment - sCustomBufferSize.nBufferSize = ALIGN(sCustomBufferSize.nBufferSize, SZ_4K); - - err = mOMX->setParameter(mNode, - (OMX_INDEXTYPE)OMX_QcomIndexParamVideoCustomBufferSize, - &sCustomBufferSize, sizeof(sCustomBufferSize)); - - if (err != OK) { - ALOGE("[%s] Set Inputbuffers thru extn size %lu InputPort Failed", - mComponentName.c_str(), - sCustomBufferSize.nBufferSize); - } - else - { - ALOGV("[%s] Set Inputbuffers thru extn size %lu InputPort Success", - mComponentName.c_str(), - sCustomBufferSize.nBufferSize); - } - - //Enable component support to extract SEI extradata if present in AVC stream - QOMX_ENABLETYPE extra_data; - extra_data.bEnable = OMX_TRUE; - - status_t errVal = mOMX->setParameter( - mNode, (OMX_INDEXTYPE)OMX_QcomIndexEnableExtnUserData, - (OMX_PTR)&extra_data, sizeof(extra_data)); - - if (errVal != OK) { - ALOGE("[%s] setting OMX_QcomIndexEnableExtnUserData failed: %d", - mComponentName.c_str(), err); - } - else - { - ALOGE("[%s] setting OMX_QcomIndexEnableExtnUserData success", - mComponentName.c_str()); - } - } - } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AAC)) { - int32_t numChannels = 0, sampleRate = 0; - if (!msg->findInt32("channel-count", &numChannels) - || !msg->findInt32("sample-rate", &sampleRate)) { - err = INVALID_OPERATION; - } else { - int32_t isADTS, aacProfile; - if (!msg->findInt32("is-adts", &isADTS)) { - isADTS = 0; - } - if (!msg->findInt32("aac-profile", &aacProfile)) { - aacProfile = OMX_AUDIO_AACObjectNull; - } - - err = setupAACCodec( - encoder, numChannels, sampleRate, bitRate, aacProfile, isADTS != 0); - } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_NB)) { - err = setupAMRCodec(encoder, false /* isWAMR */, bitRate); - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AMR_WB)) { - err = setupAMRCodec(encoder, true /* isWAMR */, bitRate); - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_ALAW) - || !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_G711_MLAW)) { - // These are PCM-like formats with a fixed sample rate but - // a variable number of channels. - - int32_t numChannels = 0; - if (!msg->findInt32("channel-count", &numChannels)) { - err = INVALID_OPERATION; - } else { - err = setupG711Codec(encoder, numChannels); - } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_FLAC)) { - int32_t numChannels = 0, sampleRate = 0, compressionLevel = -1; - if (encoder && - (!msg->findInt32("channel-count", &numChannels) - || !msg->findInt32("sample-rate", &sampleRate))) { - ALOGE("missing channel count or sample rate for FLAC encoder"); - err = INVALID_OPERATION; - } else { - if (encoder) { - if (!msg->findInt32("flac-compression-level", &compressionLevel)) { - compressionLevel = 5;// default FLAC compression level - } else if (compressionLevel < 0) { - ALOGW("compression level %d outside [0..8] range, using 0", compressionLevel); - compressionLevel = 0; - } else if (compressionLevel > 8) { - ALOGW("compression level %d outside [0..8] range, using 8", compressionLevel); - compressionLevel = 8; - } - } - err = setupFlacCodec(encoder, numChannels, sampleRate, compressionLevel); - } - } else if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_RAW)) { - int32_t numChannels =0 , sampleRate = 0; - if (encoder - || !msg->findInt32("channel-count", &numChannels) - || !msg->findInt32("sample-rate", &sampleRate)) { - err = INVALID_OPERATION; - } else { - err = setupRawAudioFormat(kPortIndexInput, sampleRate, numChannels); - } - } - - if (!msg->findInt32("encoder-delay", &mEncoderDelay)) { - mEncoderDelay = 0; - } - - if (!msg->findInt32("encoder-padding", &mEncoderPadding)) { - mEncoderPadding = 0; - } - - if (msg->findInt32("channel-mask", &mChannelMask)) { - mChannelMaskPresent = true; - } else { - mChannelMaskPresent = false; - } - - int32_t maxInputSize; - if (msg->findInt32("max-input-size", &maxInputSize)) { - err = setMinBufferSize(kPortIndexInput, (size_t)maxInputSize); - } else if (!strcmp("OMX.Nvidia.aac.decoder", mComponentName.c_str())) { - err = setMinBufferSize(kPortIndexInput, 8192); // XXX - } - - return err; -} - -status_t DashCodec::setMinBufferSize(OMX_U32 portIndex, size_t size) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - if (def.nBufferSize >= size) { - return OK; - } - - def.nBufferSize = size; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - CHECK(def.nBufferSize >= size); - - return OK; -} - -status_t DashCodec::selectAudioPortFormat( - OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat) { - OMX_AUDIO_PARAM_PORTFORMATTYPE format; - InitOMXParams(&format); - - format.nPortIndex = portIndex; - for (OMX_U32 index = 0;; ++index) { - format.nIndex = index; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamAudioPortFormat, - &format, sizeof(format)); - - if (err != OK) { - return err; - } - - if (format.eEncoding == desiredFormat) { - break; - } - } - - return mOMX->setParameter( - mNode, OMX_IndexParamAudioPortFormat, &format, sizeof(format)); -} - -status_t DashCodec::setupAACCodec( - bool encoder, int32_t numChannels, int32_t sampleRate, - int32_t bitRate, int32_t aacProfile, bool isADTS) { - if (encoder && isADTS) { - return -EINVAL; - } - - status_t err = setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, - sampleRate, - numChannels); - - if (err != OK) { - return err; - } - - if (encoder) { - err = selectAudioPortFormat(kPortIndexOutput, OMX_AUDIO_CodingAAC); - - if (err != OK) { - return err; - } - - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - def.format.audio.bFlagErrorConcealment = OMX_TRUE; - def.format.audio.eEncoding = OMX_AUDIO_CodingAAC; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - OMX_AUDIO_PARAM_AACPROFILETYPE profile; - InitOMXParams(&profile); - profile.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); - - if (err != OK) { - return err; - } - - profile.nChannels = numChannels; - - profile.eChannelMode = - (numChannels == 1) - ? OMX_AUDIO_ChannelModeMono: OMX_AUDIO_ChannelModeStereo; - - profile.nSampleRate = sampleRate; - profile.nBitRate = bitRate; - profile.nAudioBandWidth = 0; - profile.nFrameLength = 0; - profile.nAACtools = OMX_AUDIO_AACToolAll; - profile.nAACERtools = OMX_AUDIO_AACERNone; - profile.eAACProfile = (OMX_AUDIO_AACPROFILETYPE) aacProfile; - profile.eAACStreamFormat = OMX_AUDIO_AACStreamFormatMP4FF; - - err = mOMX->setParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); - - if (err != OK) { - return err; - } - - return err; - } - - OMX_AUDIO_PARAM_AACPROFILETYPE profile; - InitOMXParams(&profile); - profile.nPortIndex = kPortIndexInput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); - - if (err != OK) { - return err; - } - - profile.nChannels = numChannels; - profile.nSampleRate = sampleRate; - - profile.eAACStreamFormat = - isADTS - ? OMX_AUDIO_AACStreamFormatMP4ADTS - : OMX_AUDIO_AACStreamFormatMP4FF; - - return mOMX->setParameter( - mNode, OMX_IndexParamAudioAac, &profile, sizeof(profile)); -} - -static OMX_AUDIO_AMRBANDMODETYPE pickModeFromBitRate( - bool isAMRWB, int32_t bps) { - if (isAMRWB) { - if (bps <= 6600) { - return OMX_AUDIO_AMRBandModeWB0; - } else if (bps <= 8850) { - return OMX_AUDIO_AMRBandModeWB1; - } else if (bps <= 12650) { - return OMX_AUDIO_AMRBandModeWB2; - } else if (bps <= 14250) { - return OMX_AUDIO_AMRBandModeWB3; - } else if (bps <= 15850) { - return OMX_AUDIO_AMRBandModeWB4; - } else if (bps <= 18250) { - return OMX_AUDIO_AMRBandModeWB5; - } else if (bps <= 19850) { - return OMX_AUDIO_AMRBandModeWB6; - } else if (bps <= 23050) { - return OMX_AUDIO_AMRBandModeWB7; - } - - // 23850 bps - return OMX_AUDIO_AMRBandModeWB8; - } else { // AMRNB - if (bps <= 4750) { - return OMX_AUDIO_AMRBandModeNB0; - } else if (bps <= 5150) { - return OMX_AUDIO_AMRBandModeNB1; - } else if (bps <= 5900) { - return OMX_AUDIO_AMRBandModeNB2; - } else if (bps <= 6700) { - return OMX_AUDIO_AMRBandModeNB3; - } else if (bps <= 7400) { - return OMX_AUDIO_AMRBandModeNB4; - } else if (bps <= 7950) { - return OMX_AUDIO_AMRBandModeNB5; - } else if (bps <= 10200) { - return OMX_AUDIO_AMRBandModeNB6; - } - - // 12200 bps - return OMX_AUDIO_AMRBandModeNB7; - } -} - -status_t DashCodec::setupAMRCodec(bool encoder, bool isWAMR, int32_t bitrate) { - OMX_AUDIO_PARAM_AMRTYPE def; - InitOMXParams(&def); - def.nPortIndex = encoder ? kPortIndexOutput : kPortIndexInput; - - status_t err = - mOMX->getParameter(mNode, OMX_IndexParamAudioAmr, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - def.eAMRFrameFormat = OMX_AUDIO_AMRFrameFormatFSF; - def.eAMRBandMode = pickModeFromBitRate(isWAMR, bitrate); - - err = mOMX->setParameter( - mNode, OMX_IndexParamAudioAmr, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - return setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, - isWAMR ? 16000 : 8000 /* sampleRate */, - 1 /* numChannels */); -} - -status_t DashCodec::setupG711Codec(bool encoder, int32_t numChannels) { - CHECK(!encoder); // XXX TODO - - return setupRawAudioFormat( - kPortIndexInput, 8000 /* sampleRate */, numChannels); -} - -status_t DashCodec::setupFlacCodec( - bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel) { - - if (encoder) { - OMX_AUDIO_PARAM_FLACTYPE def; - InitOMXParams(&def); - def.nPortIndex = kPortIndexOutput; - - // configure compression level - status_t err = mOMX->getParameter(mNode, OMX_IndexParamAudioFlac, &def, sizeof(def)); - if (err != OK) { - ALOGE("setupFlacCodec(): Error %d getting OMX_IndexParamAudioFlac parameter", err); - return err; - } - def.nCompressionLevel = compressionLevel; - err = mOMX->setParameter(mNode, OMX_IndexParamAudioFlac, &def, sizeof(def)); - if (err != OK) { - ALOGE("setupFlacCodec(): Error %d setting OMX_IndexParamAudioFlac parameter", err); - return err; - } - } - - return setupRawAudioFormat( - encoder ? kPortIndexInput : kPortIndexOutput, - sampleRate, - numChannels); -} - -status_t DashCodec::setupRawAudioFormat( - OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - def.format.audio.eEncoding = OMX_AUDIO_CodingPCM; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - OMX_AUDIO_PARAM_PCMMODETYPE pcmParams; - InitOMXParams(&pcmParams); - pcmParams.nPortIndex = portIndex; - - err = mOMX->getParameter( - mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); - - if (err != OK) { - return err; - } - - pcmParams.nChannels = numChannels; - pcmParams.eNumData = OMX_NumericalDataSigned; - pcmParams.bInterleaved = OMX_TRUE; - pcmParams.nBitPerSample = 16; - pcmParams.nSamplingRate = sampleRate; - pcmParams.ePCMMode = OMX_AUDIO_PCMModeLinear; - - if (getOMXChannelMapping(numChannels, pcmParams.eChannelMapping) != OK) { - return OMX_ErrorNone; - } - - return mOMX->setParameter( - mNode, OMX_IndexParamAudioPcm, &pcmParams, sizeof(pcmParams)); -} - -status_t DashCodec::setVideoPortFormatType( - OMX_U32 portIndex, - OMX_VIDEO_CODINGTYPE compressionFormat, - OMX_COLOR_FORMATTYPE colorFormat) { - OMX_VIDEO_PARAM_PORTFORMATTYPE format; - InitOMXParams(&format); - format.nPortIndex = portIndex; - format.nIndex = 0; - bool found = false; - - OMX_U32 index = 0; - for (;;) { - format.nIndex = index; - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - - if (err != OK) { - return err; - } - - // The following assertion is violated by TI's video decoder. - // CHECK_EQ(format.nIndex, index); - - if (!strcmp("OMX.TI.Video.encoder", mComponentName.c_str())) { - if (portIndex == kPortIndexInput - && colorFormat == format.eColorFormat) { - // eCompressionFormat does not seem right. - found = true; - break; - } - if (portIndex == kPortIndexOutput - && compressionFormat == format.eCompressionFormat) { - // eColorFormat does not seem right. - found = true; - break; - } - } - - if (format.eCompressionFormat == compressionFormat - && format.eColorFormat == colorFormat) { - found = true; - break; - } - - ++index; - } - - if (!found) { - return UNKNOWN_ERROR; - } - - status_t err = mOMX->setParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - - return err; -} - -status_t DashCodec::setSupportedOutputFormat() { - OMX_VIDEO_PARAM_PORTFORMATTYPE format; - InitOMXParams(&format); - format.nPortIndex = kPortIndexOutput; - format.nIndex = 0; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); - CHECK_EQ(err, (status_t)OK); - CHECK_EQ((int)format.eCompressionFormat, (int)OMX_VIDEO_CodingUnused); - - CHECK(format.eColorFormat == OMX_COLOR_FormatYUV420Planar - || format.eColorFormat == OMX_COLOR_FormatYUV420SemiPlanar - || format.eColorFormat == OMX_COLOR_FormatCbYCrY - || format.eColorFormat == OMX_TI_COLOR_FormatYUV420PackedSemiPlanar - || format.eColorFormat == OMX_QCOM_COLOR_FormatYVU420SemiPlanar - || format.eColorFormat == OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar64x32Tile2m8ka - || format.eColorFormat == (OMX_COLOR_FORMATTYPE)QOMX_COLOR_FORMATYUV420PackedSemiPlanar32m - ); - - return mOMX->setParameter( - mNode, OMX_IndexParamVideoPortFormat, - &format, sizeof(format)); -} - -static status_t GetVideoCodingTypeFromMime( - const char *mime, OMX_VIDEO_CODINGTYPE *codingType) { - if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime)) { - *codingType = OMX_VIDEO_CodingAVC; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG4, mime)) { - *codingType = OMX_VIDEO_CodingMPEG4; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_H263, mime)) { - *codingType = OMX_VIDEO_CodingH263; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_MPEG2, mime)) { - *codingType = OMX_VIDEO_CodingMPEG2; - } else if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_HEVC, mime)) { - *codingType = (OMX_VIDEO_CODINGTYPE)QOMX_VIDEO_CodingHevc; - } else { - *codingType = OMX_VIDEO_CodingUnused; - return ERROR_UNSUPPORTED; - } - - return OK; -} - -status_t DashCodec::setupVideoDecoder( - const char *mime, int32_t width, int32_t height) { - OMX_VIDEO_CODINGTYPE compressionFormat; - status_t err = GetVideoCodingTypeFromMime(mime, &compressionFormat); - - if (err != OK) { - return err; - } - - err = setVideoPortFormatType( - kPortIndexInput, compressionFormat, OMX_COLOR_FormatUnused); - - if (err != OK) { - return err; - } - - err = setSupportedOutputFormat(); - - if (err != OK) { - return err; - } - - err = setVideoFormatOnPort( - kPortIndexInput, width, height, compressionFormat); - - if (err != OK) { - return err; - } - - err = setVideoFormatOnPort( - kPortIndexOutput, width, height, OMX_VIDEO_CodingUnused); - - if (err != OK) { - return err; - } - - return OK; -} - -status_t DashCodec::setupVideoEncoder(const char *mime, const sp<AMessage> &msg) { - int32_t tmp; - if (!msg->findInt32("color-format", &tmp)) { - return INVALID_OPERATION; - } - - OMX_COLOR_FORMATTYPE colorFormat = - static_cast<OMX_COLOR_FORMATTYPE>(tmp); - - status_t err = setVideoPortFormatType( - kPortIndexInput, OMX_VIDEO_CodingUnused, colorFormat); - - if (err != OK) { - ALOGE("[%s] does not support color format %d", - mComponentName.c_str(), colorFormat); - - return err; - } - - /* Input port configuration */ - - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - - def.nPortIndex = kPortIndexInput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - int32_t width, height, bitrate; - if (!msg->findInt32("width", &width) - || !msg->findInt32("height", &height) - || !msg->findInt32("bitrate", &bitrate)) { - return INVALID_OPERATION; - } - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - - int32_t stride; - if (!msg->findInt32("stride", &stride)) { - stride = width; - } - - video_def->nStride = stride; - - int32_t sliceHeight; - if (!msg->findInt32("slice-height", &sliceHeight)) { - sliceHeight = height; - } - - video_def->nSliceHeight = sliceHeight; - - def.nBufferSize = (video_def->nStride * video_def->nSliceHeight * 3) / 2; - - float frameRate; - if (!msg->findFloat("frame-rate", &frameRate)) { - int32_t tmp; - if (!msg->findInt32("frame-rate", &tmp)) { - return INVALID_OPERATION; - } - frameRate = (float)tmp; - } - - video_def->xFramerate = (OMX_U32)(frameRate * 65536.0f); - video_def->eCompressionFormat = OMX_VIDEO_CodingUnused; - video_def->eColorFormat = colorFormat; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - ALOGE("[%s] failed to set input port definition parameters.", - mComponentName.c_str()); - - return err; - } - - /* Output port configuration */ - - OMX_VIDEO_CODINGTYPE compressionFormat; - err = GetVideoCodingTypeFromMime(mime, &compressionFormat); - - if (err != OK) { - return err; - } - - err = setVideoPortFormatType( - kPortIndexOutput, compressionFormat, OMX_COLOR_FormatUnused); - - if (err != OK) { - ALOGE("[%s] does not support compression format %d", - mComponentName.c_str(), compressionFormat); - - return err; - } - - def.nPortIndex = kPortIndexOutput; - - err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - return err; - } - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - video_def->xFramerate = 0; - video_def->nBitrate = bitrate; - video_def->eCompressionFormat = compressionFormat; - video_def->eColorFormat = OMX_COLOR_FormatUnused; - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - if (err != OK) { - ALOGE("[%s] failed to set output port definition parameters.", - mComponentName.c_str()); - - return err; - } - - switch (compressionFormat) { - case OMX_VIDEO_CodingMPEG4: - err = setupMPEG4EncoderParameters(msg); - break; - - case OMX_VIDEO_CodingH263: - err = setupH263EncoderParameters(msg); - break; - - case OMX_VIDEO_CodingAVC: - err = setupAVCEncoderParameters(msg); - break; - - default: - break; - } - - ALOGI("setupVideoEncoder succeeded"); - - return err; -} - -static OMX_U32 setPFramesSpacing(int32_t iFramesInterval, int32_t frameRate) { - if (iFramesInterval < 0) { - return 0xFFFFFFFF; - } else if (iFramesInterval == 0) { - return 0; - } - OMX_U32 ret = frameRate * iFramesInterval; - CHECK(ret > 1); - return ret; -} - -static OMX_VIDEO_CONTROLRATETYPE getBitrateMode(const sp<AMessage> &msg) { - int32_t tmp; - if (!msg->findInt32("bitrate-mode", &tmp)) { - return OMX_Video_ControlRateVariable; - } - - return static_cast<OMX_VIDEO_CONTROLRATETYPE>(tmp); -} - -status_t DashCodec::setupMPEG4EncoderParameters(const sp<AMessage> &msg) { - int32_t bitrate, iFrameInterval; - if (!msg->findInt32("bitrate", &bitrate) - || !msg->findInt32("i-frame-interval", &iFrameInterval)) { - return INVALID_OPERATION; - } - - OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg); - - float frameRate; - if (!msg->findFloat("frame-rate", &frameRate)) { - int32_t tmp; - if (!msg->findInt32("frame-rate", &tmp)) { - return INVALID_OPERATION; - } - frameRate = (float)tmp; - } - - OMX_VIDEO_PARAM_MPEG4TYPE mpeg4type; - InitOMXParams(&mpeg4type); - mpeg4type.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); - - if (err != OK) { - return err; - } - - mpeg4type.nSliceHeaderSpacing = 0; - mpeg4type.bSVH = OMX_FALSE; - mpeg4type.bGov = OMX_FALSE; - - mpeg4type.nAllowedPictureTypes = - OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - - mpeg4type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate); - if (mpeg4type.nPFrames == 0) { - mpeg4type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; - } - mpeg4type.nBFrames = 0; - mpeg4type.nIDCVLCThreshold = 0; - mpeg4type.bACPred = OMX_TRUE; - mpeg4type.nMaxPacketSize = 256; - mpeg4type.nTimeIncRes = 1000; - mpeg4type.nHeaderExtension = 0; - mpeg4type.bReversibleVLC = OMX_FALSE; - - int32_t profile; - if (msg->findInt32("profile", &profile)) { - int32_t level; - if (!msg->findInt32("level", &level)) { - return INVALID_OPERATION; - } - - err = verifySupportForProfileAndLevel(profile, level); - - if (err != OK) { - return err; - } - - mpeg4type.eProfile = static_cast<OMX_VIDEO_MPEG4PROFILETYPE>(profile); - mpeg4type.eLevel = static_cast<OMX_VIDEO_MPEG4LEVELTYPE>(level); - } - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoMpeg4, &mpeg4type, sizeof(mpeg4type)); - - if (err != OK) { - return err; - } - - err = configureBitrate(bitrate, bitrateMode); - - if (err != OK) { - return err; - } - - return setupErrorCorrectionParameters(); -} - -status_t DashCodec::setupH263EncoderParameters(const sp<AMessage> &msg) { - int32_t bitrate, iFrameInterval; - if (!msg->findInt32("bitrate", &bitrate) - || !msg->findInt32("i-frame-interval", &iFrameInterval)) { - return INVALID_OPERATION; - } - - OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg); - - float frameRate; - if (!msg->findFloat("frame-rate", &frameRate)) { - int32_t tmp; - if (!msg->findInt32("frame-rate", &tmp)) { - return INVALID_OPERATION; - } - frameRate = (float)tmp; - } - - OMX_VIDEO_PARAM_H263TYPE h263type; - InitOMXParams(&h263type); - h263type.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type)); - - if (err != OK) { - return err; - } - - h263type.nAllowedPictureTypes = - OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - - h263type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate); - if (h263type.nPFrames == 0) { - h263type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; - } - h263type.nBFrames = 0; - - int32_t profile; - if (msg->findInt32("profile", &profile)) { - int32_t level; - if (!msg->findInt32("level", &level)) { - return INVALID_OPERATION; - } - - err = verifySupportForProfileAndLevel(profile, level); - - if (err != OK) { - return err; - } - - h263type.eProfile = static_cast<OMX_VIDEO_H263PROFILETYPE>(profile); - h263type.eLevel = static_cast<OMX_VIDEO_H263LEVELTYPE>(level); - } - - h263type.bPLUSPTYPEAllowed = OMX_FALSE; - h263type.bForceRoundingTypeToZero = OMX_FALSE; - h263type.nPictureHeaderRepetition = 0; - h263type.nGOBHeaderInterval = 0; - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoH263, &h263type, sizeof(h263type)); - - if (err != OK) { - return err; - } - - err = configureBitrate(bitrate, bitrateMode); - - if (err != OK) { - return err; - } - - return setupErrorCorrectionParameters(); -} - -status_t DashCodec::setupAVCEncoderParameters(const sp<AMessage> &msg) { - int32_t bitrate, iFrameInterval; - if (!msg->findInt32("bitrate", &bitrate) - || !msg->findInt32("i-frame-interval", &iFrameInterval)) { - return INVALID_OPERATION; - } - - OMX_VIDEO_CONTROLRATETYPE bitrateMode = getBitrateMode(msg); - - float frameRate; - if (!msg->findFloat("frame-rate", &frameRate)) { - int32_t tmp; - if (!msg->findInt32("frame-rate", &tmp)) { - return INVALID_OPERATION; - } - frameRate = (float)tmp; - } - - OMX_VIDEO_PARAM_AVCTYPE h264type; - InitOMXParams(&h264type); - h264type.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type)); - - if (err != OK) { - return err; - } - - h264type.nAllowedPictureTypes = - OMX_VIDEO_PictureTypeI | OMX_VIDEO_PictureTypeP; - - int32_t profile; - if (msg->findInt32("profile", &profile)) { - int32_t level; - if (!msg->findInt32("level", &level)) { - return INVALID_OPERATION; - } - - err = verifySupportForProfileAndLevel(profile, level); - - if (err != OK) { - return err; - } - - h264type.eProfile = static_cast<OMX_VIDEO_AVCPROFILETYPE>(profile); - h264type.eLevel = static_cast<OMX_VIDEO_AVCLEVELTYPE>(level); - } - - // XXX - if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline) { - ALOGW("Use baseline profile instead of %d for AVC recording", - h264type.eProfile); - h264type.eProfile = OMX_VIDEO_AVCProfileBaseline; - } - - if (h264type.eProfile == OMX_VIDEO_AVCProfileBaseline) { - h264type.nSliceHeaderSpacing = 0; - h264type.bUseHadamard = OMX_TRUE; - h264type.nRefFrames = 1; - h264type.nBFrames = 0; - h264type.nPFrames = setPFramesSpacing(iFrameInterval, frameRate); - if (h264type.nPFrames == 0) { - h264type.nAllowedPictureTypes = OMX_VIDEO_PictureTypeI; - } - h264type.nRefIdx10ActiveMinus1 = 0; - h264type.nRefIdx11ActiveMinus1 = 0; - h264type.bEntropyCodingCABAC = OMX_FALSE; - h264type.bWeightedPPrediction = OMX_FALSE; - h264type.bconstIpred = OMX_FALSE; - h264type.bDirect8x8Inference = OMX_FALSE; - h264type.bDirectSpatialTemporal = OMX_FALSE; - h264type.nCabacInitIdc = 0; - } - - if (h264type.nBFrames != 0) { - h264type.nAllowedPictureTypes |= OMX_VIDEO_PictureTypeB; - } - - h264type.bEnableUEP = OMX_FALSE; - h264type.bEnableFMO = OMX_FALSE; - h264type.bEnableASO = OMX_FALSE; - h264type.bEnableRS = OMX_FALSE; - h264type.bFrameMBsOnly = OMX_TRUE; - h264type.bMBAFF = OMX_FALSE; - h264type.eLoopFilterMode = OMX_VIDEO_AVCLoopFilterEnable; - - err = mOMX->setParameter( - mNode, OMX_IndexParamVideoAvc, &h264type, sizeof(h264type)); - - if (err != OK) { - return err; - } - - return configureBitrate(bitrate, bitrateMode); -} - -status_t DashCodec::verifySupportForProfileAndLevel( - int32_t profile, int32_t level) { - OMX_VIDEO_PARAM_PROFILELEVELTYPE params; - InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; - - for (params.nProfileIndex = 0;; ++params.nProfileIndex) { - status_t err = mOMX->getParameter( - mNode, - OMX_IndexParamVideoProfileLevelQuerySupported, - ¶ms, - sizeof(params)); - - if (err != OK) { - return err; - } - - int32_t supportedProfile = static_cast<int32_t>(params.eProfile); - int32_t supportedLevel = static_cast<int32_t>(params.eLevel); - - if (profile == supportedProfile && level <= supportedLevel) { - return OK; - } - } -} - -status_t DashCodec::configureBitrate( - int32_t bitrate, OMX_VIDEO_CONTROLRATETYPE bitrateMode) { - OMX_VIDEO_PARAM_BITRATETYPE bitrateType; - InitOMXParams(&bitrateType); - bitrateType.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoBitrate, - &bitrateType, sizeof(bitrateType)); - - if (err != OK) { - return err; - } - - bitrateType.eControlRate = bitrateMode; - bitrateType.nTargetBitrate = bitrate; - - return mOMX->setParameter( - mNode, OMX_IndexParamVideoBitrate, - &bitrateType, sizeof(bitrateType)); -} - -status_t DashCodec::setupErrorCorrectionParameters() { - OMX_VIDEO_PARAM_ERRORCORRECTIONTYPE errorCorrectionType; - InitOMXParams(&errorCorrectionType); - errorCorrectionType.nPortIndex = kPortIndexOutput; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamVideoErrorCorrection, - &errorCorrectionType, sizeof(errorCorrectionType)); - - if (err != OK) { - return OK; // Optional feature. Ignore this failure - } - - errorCorrectionType.bEnableHEC = OMX_FALSE; - errorCorrectionType.bEnableResync = OMX_TRUE; - errorCorrectionType.nResynchMarkerSpacing = 256; - errorCorrectionType.bEnableDataPartitioning = OMX_FALSE; - errorCorrectionType.bEnableRVLC = OMX_FALSE; - - return mOMX->setParameter( - mNode, OMX_IndexParamVideoErrorCorrection, - &errorCorrectionType, sizeof(errorCorrectionType)); -} - -status_t DashCodec::setVideoFormatOnPort( - OMX_U32 portIndex, - int32_t width, int32_t height, OMX_VIDEO_CODINGTYPE compressionFormat) { - OMX_PARAM_PORTDEFINITIONTYPE def; - InitOMXParams(&def); - def.nPortIndex = portIndex; - - OMX_VIDEO_PORTDEFINITIONTYPE *video_def = &def.format.video; - - status_t err = mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - CHECK_EQ(err, (status_t)OK); - - if (portIndex == kPortIndexInput) { - // XXX Need a (much) better heuristic to compute input buffer sizes. - const size_t X = 64 * 1024; - if (def.nBufferSize < X) { - def.nBufferSize = X; - } - } - - CHECK_EQ((int)def.eDomain, (int)OMX_PortDomainVideo); - - video_def->nFrameWidth = width; - video_def->nFrameHeight = height; - - if (portIndex == kPortIndexInput) { - video_def->eCompressionFormat = compressionFormat; - video_def->eColorFormat = OMX_COLOR_FormatUnused; - } - - err = mOMX->setParameter( - mNode, OMX_IndexParamPortDefinition, &def, sizeof(def)); - - return err; -} - -status_t DashCodec::initNativeWindow() { - if (mNativeWindow != NULL) { - return mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_TRUE); - } - - mOMX->enableGraphicBuffers(mNode, kPortIndexOutput, OMX_FALSE); - return OK; -} - -size_t DashCodec::countBuffersOwnedByComponent(OMX_U32 portIndex) const { - size_t n = 0; - - for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) { - const BufferInfo &info = mBuffers[portIndex].itemAt(i); - - if (info.mStatus == BufferInfo::OWNED_BY_COMPONENT) { - ++n; - } - } - - return n; -} - -size_t DashCodec::countBuffersOwnedByNativeWindow() const { - size_t n = 0; - - for (size_t i = 0; i < mBuffers[kPortIndexOutput].size(); ++i) { - const BufferInfo &info = mBuffers[kPortIndexOutput].itemAt(i); - - if (info.mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { - ++n; - } - } - - return n; -} - -void DashCodec::waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs() { - if (mNativeWindow == NULL) { - return; - } - - int minUndequeuedBufs = 0; - status_t err = mNativeWindow->query( - mNativeWindow.get(), NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, - &minUndequeuedBufs); - - if (err != OK) { - ALOGE("[%s] NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS query failed: %s (%d)", - mComponentName.c_str(), strerror(-err), -err); - - minUndequeuedBufs = 0; - } - - while (countBuffersOwnedByNativeWindow() > (size_t)minUndequeuedBufs - && dequeueBufferFromNativeWindow() != NULL) { - // these buffers will be submitted as regular buffers; account for this - if (mStoreMetaDataInOutputBuffers && mMetaDataBuffersToSubmit > 0) { - --mMetaDataBuffersToSubmit; - } - } -} - -bool DashCodec::allYourBuffersAreBelongToUs( - OMX_U32 portIndex) { - for (size_t i = 0; i < mBuffers[portIndex].size(); ++i) { - BufferInfo *info = &mBuffers[portIndex].editItemAt(i); - - if (info->mStatus != BufferInfo::OWNED_BY_US - && info->mStatus != BufferInfo::OWNED_BY_NATIVE_WINDOW) { - ALOGV("[%s] Buffer %p on port %ld still has status %d", - mComponentName.c_str(), - info->mBufferID, portIndex, info->mStatus); - return false; - } - } - - return true; -} - -bool DashCodec::allYourBuffersAreBelongToUs() { - return allYourBuffersAreBelongToUs(kPortIndexInput) - && allYourBuffersAreBelongToUs(kPortIndexOutput); -} - -void DashCodec::deferMessage(const sp<AMessage> &msg) { - bool wasEmptyBefore = mDeferredQueue.empty(); - mDeferredQueue.push_back(msg); -} - -void DashCodec::processDeferredMessages() { - List<sp<AMessage> > queue = mDeferredQueue; - mDeferredQueue.clear(); - - List<sp<AMessage> >::iterator it = queue.begin(); - while (it != queue.end()) { - onMessageReceived(*it++); - } -} - -void DashCodec::queueNextFormat() { - OMX_PARAM_PORTDEFINITIONTYPE* def = new OMX_PARAM_PORTDEFINITIONTYPE(); - InitOMXParams(def); - def->nPortIndex = kPortIndexOutput; - - CHECK_EQ(mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, def, sizeof(*def)), - (status_t)OK); - - CHECK_EQ((int)def->eDir, (int)OMX_DirOutput); - mFormats.push_back(def); - - OMX_CONFIG_RECTTYPE* rect = new OMX_CONFIG_RECTTYPE(); - InitOMXParams(rect); - rect->nPortIndex = kPortIndexOutput; - if (mOMX->getConfig(mNode, OMX_IndexConfigCommonOutputCrop, rect, sizeof(*rect)) != OK) { - mOutputCrops.push_back(NULL); - } else { - mOutputCrops.push_back(rect); - } -} - -void DashCodec::clearCachedFormats() { - for (size_t i = 0 ; i < mOutputCrops.size(); i++) - { - if (mOutputCrops[i]) - { - delete mOutputCrops[i]; - } - } - for (size_t i = 0 ; i < mFormats.size(); i++) - { - if (mFormats[i]) - { - delete mFormats[i]; - } - } - mOutputCrops.clear(); - mFormats.clear(); -} - -void DashCodec::sendFormatChange() { - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatOutputFormatChanged); - bool useCachedConfig = false; - OMX_PARAM_PORTDEFINITIONTYPE* def; - if (mFormats.size() > 0) { - useCachedConfig = true; - def = mFormats[0]; - mFormats.removeAt(0); - } else { - def = new OMX_PARAM_PORTDEFINITIONTYPE(); - InitOMXParams(def); - def->nPortIndex = kPortIndexOutput; - - CHECK_EQ(mOMX->getParameter( - mNode, OMX_IndexParamPortDefinition, def, sizeof(*def)), - (status_t)OK); - - CHECK_EQ((int)def->eDir, (int)OMX_DirOutput); - } - switch (def->eDomain) { - case OMX_PortDomainVideo: - { - OMX_VIDEO_PORTDEFINITIONTYPE *videoDef = &def->format.video; - - notify->setString("mime", MEDIA_MIMETYPE_VIDEO_RAW); - notify->setInt32("width", videoDef->nFrameWidth); - notify->setInt32("height", videoDef->nFrameHeight); - notify->setInt32("stride", videoDef->nStride); - notify->setInt32("slice-height", videoDef->nSliceHeight); - notify->setInt32("color-format", videoDef->eColorFormat); - ALOGV("sendformatchange: %lu %lu", videoDef->nFrameWidth, videoDef->nFrameHeight); - - //If dynamic buffering mode cache the latest width and height. Will be used for VENUS macors to calculate filledLen in fbd's. - if(mStoreMetaDataInOutputBuffers) - { - mCurrentWidth = videoDef->nFrameWidth; - mCurrentHeight = videoDef->nFrameHeight; - } - - OMX_CONFIG_RECTTYPE* rect; - bool hasValidCrop = true; - if (useCachedConfig) { - rect = mOutputCrops[0]; - mOutputCrops.removeAt(0); - if (rect == NULL) { - rect = new OMX_CONFIG_RECTTYPE(); - hasValidCrop = false; - } - } else { - rect = new OMX_CONFIG_RECTTYPE(); - InitOMXParams(rect); - rect->nPortIndex = kPortIndexOutput; - hasValidCrop = (mOMX->getConfig( - mNode, OMX_IndexConfigCommonOutputCrop, - rect, sizeof(*rect)) == OK); - } - - if (!hasValidCrop) { - rect->nLeft = 0; - rect->nTop = 0; - rect->nWidth = videoDef->nFrameWidth; - rect->nHeight = videoDef->nFrameHeight; - } - - CHECK_GE(rect->nLeft, 0); - CHECK_GE(rect->nTop, 0); - CHECK_GE(rect->nWidth, 0u); - CHECK_GE(rect->nHeight, 0u); - CHECK_LE(rect->nLeft + rect->nWidth - 1, videoDef->nFrameWidth); - CHECK_LE(rect->nTop + rect->nHeight - 1, videoDef->nFrameHeight); - - notify->setRect( - "crop", - rect->nLeft, - rect->nTop, - rect->nLeft + rect->nWidth - 1, - rect->nTop + rect->nHeight - 1); - - if (mNativeWindow != NULL) { - android_native_rect_t crop; - crop.left = rect->nLeft; - crop.top = rect->nTop; - crop.right = rect->nLeft + rect->nWidth; - crop.bottom = rect->nTop + rect->nHeight; - - CHECK_EQ(0, native_window_set_crop( - mNativeWindow.get(), &crop)); - } - delete rect; - break; - } - - case OMX_PortDomainAudio: - { - OMX_AUDIO_PORTDEFINITIONTYPE *audioDef = &def->format.audio; - CHECK_EQ((int)audioDef->eEncoding, (int)OMX_AUDIO_CodingPCM); - - OMX_AUDIO_PARAM_PCMMODETYPE params; - InitOMXParams(¶ms); - params.nPortIndex = kPortIndexOutput; - - CHECK_EQ(mOMX->getParameter( - mNode, OMX_IndexParamAudioPcm, - ¶ms, sizeof(params)), - (status_t)OK); - - CHECK(params.nChannels == 1 || params.bInterleaved); - CHECK_EQ(params.nBitPerSample, 16u); - CHECK_EQ((int)params.eNumData, (int)OMX_NumericalDataSigned); - CHECK_EQ((int)params.ePCMMode, (int)OMX_AUDIO_PCMModeLinear); - - notify->setString("mime", MEDIA_MIMETYPE_AUDIO_RAW); - notify->setInt32("channel-count", params.nChannels); - notify->setInt32("sample-rate", params.nSamplingRate); - if (mEncoderDelay + mEncoderPadding) { - size_t frameSize = params.nChannels * sizeof(int16_t); - if (mSkipCutBuffer != NULL) { - size_t prevbufsize = mSkipCutBuffer->size(); - if (prevbufsize != 0) { - ALOGW("Replacing SkipCutBuffer holding %d bytes", prevbufsize); - } - } - mSkipCutBuffer = new SkipCutBuffer(mEncoderDelay * frameSize, - mEncoderPadding * frameSize); - } - - if (mChannelMaskPresent) { - notify->setInt32("channel-mask", mChannelMask); - } - - break; - } - - default: - TRESPASS(); - } - - notify->post(); - delete def; - mSentFormat = true; -} - -void DashCodec::signalError(OMX_ERRORTYPE error, status_t internalError) { - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatError); - notify->setInt32("omx-error", error); - notify->setInt32("err", internalError); - notify->post(); -} - -status_t DashCodec::PushBlankBuffersToNativeWindow(sp<ANativeWindow> nativeWindow) { - status_t err = NO_ERROR; - ANativeWindowBuffer* anb = NULL; - int numBufs = 0; - int minUndequeuedBufs = 0; - - // We need to reconnect to the ANativeWindow as a CPU client to ensure that - // no frames get dropped by SurfaceFlinger assuming that these are video - // frames. - err = native_window_api_disconnect(nativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_api_connect(nativeWindow.get(), - NATIVE_WINDOW_API_CPU); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_connect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_set_buffers_dimensions( - nativeWindow.get(), - 1, - 1); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: native_window_set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); - return err; - } - err = native_window_set_buffers_format( - nativeWindow.get(), - HAL_PIXEL_FORMAT_RGBX_8888); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: native_window_set_buffers_format failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_set_scaling_mode(nativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != NO_ERROR) { - ALOGE("error pushing blank_frames: set_scaling_mode failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_usage(nativeWindow.get(), - GRALLOC_USAGE_SW_WRITE_OFTEN); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_usage failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = nativeWindow->query(nativeWindow.get(), - NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " - "failed: %s (%d)", strerror(-err), -err); - goto error; - } - - numBufs = minUndequeuedBufs + 1; - err = native_window_set_buffer_count(nativeWindow.get(), numBufs); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - // We push numBufs + 1 buffers to ensure that we've drawn into the same - // buffer twice. This should guarantee that the buffer has been displayed - // on the screen and then been replaced, so an previous video frames are - // guaranteed NOT to be currently displayed. - for (int i = 0; i < numBufs + 1; i++) { - int fenceFd = -1; - err = native_window_dequeue_buffer_and_wait(nativeWindow.get(), &anb); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - - // Fill the buffer with the a 1x1 checkerboard pattern ;) - uint32_t* img = NULL; - err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: lock failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - *img = 0; - - err = buf->unlock(); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: unlock failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = nativeWindow->queueBuffer(nativeWindow.get(), - buf->getNativeBuffer(), -1); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - anb = NULL; - } - -error: - - if (err != NO_ERROR) { - // Clean up after an error. - if (anb != NULL) { - nativeWindow->cancelBuffer(nativeWindow.get(), anb, -1); - } - - native_window_api_disconnect(nativeWindow.get(), - NATIVE_WINDOW_API_CPU); - native_window_api_connect(nativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - - return err; - } else { - // Clean up after success. - err = native_window_api_disconnect(nativeWindow.get(), - NATIVE_WINDOW_API_CPU); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_api_connect(nativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_connect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - return NO_ERROR; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::PortDescription::PortDescription() { -} - -status_t DashCodec::requestIDRFrame() { - if (!mIsEncoder) { - return ERROR_UNSUPPORTED; - } - - OMX_CONFIG_INTRAREFRESHVOPTYPE params; - InitOMXParams(¶ms); - - params.nPortIndex = kPortIndexOutput; - params.IntraRefreshVOP = OMX_TRUE; - - return mOMX->setConfig( - mNode, - OMX_IndexConfigVideoIntraVOPRefresh, - ¶ms, - sizeof(params)); -} - -void DashCodec::PortDescription::addBuffer( - IOMX::buffer_id id, const sp<ABuffer> &buffer) { - mBufferIDs.push_back(id); - mBuffers.push_back(buffer); -} - -size_t DashCodec::PortDescription::countBuffers() { - return mBufferIDs.size(); -} - -IOMX::buffer_id DashCodec::PortDescription::bufferIDAt(size_t index) const { - return mBufferIDs.itemAt(index); -} - -sp<ABuffer> DashCodec::PortDescription::bufferAt(size_t index) const { - return mBuffers.itemAt(index); -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::BaseState::BaseState(DashCodec *codec, const sp<AState> &parentState) - : AState(parentState), - mCodec(codec) { -} - -DashCodec::BaseState::PortMode DashCodec::BaseState::getPortMode(OMX_U32 /*portIndex*/) { - return KEEP_BUFFERS; -} - -bool DashCodec::BaseState::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatInputBufferFilled: - { - onInputBufferFilled(msg); - break; - } - - case kWhatOutputBufferDrained: - { - onOutputBufferDrained(msg); - break; - } - - case DashCodec::kWhatOMXMessage: - { - return onOMXMessage(msg); - } - - case DashCodec::kWhatFlush: - { - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatFlushCompleted); - notify->post(); - return true; - } - - default: - return false; - } - - return true; -} - -bool DashCodec::BaseState::onOMXMessage(const sp<AMessage> &msg) { - int32_t type; - CHECK(msg->findInt32("type", &type)); - - IOMX::node_id nodeID; - CHECK(msg->findInt32("node", (int32_t*)&nodeID)); - CHECK_EQ(nodeID, mCodec->mNode); - - switch (type) { - case omx_message::EVENT: - { - int32_t event, data1, data2; - CHECK(msg->findInt32("event", &event)); - CHECK(msg->findInt32("data1", &data1)); - CHECK(msg->findInt32("data2", &data2)); - - if (event == OMX_EventCmdComplete - && data1 == OMX_CommandFlush - && data2 == (int32_t)OMX_ALL) { - // Use of this notification is not consistent across - // implementations. We'll drop this notification and rely - // on flush-complete notifications on the individual port - // indices instead. - - return true; - } - - return onOMXEvent( - static_cast<OMX_EVENTTYPE>(event), - static_cast<OMX_U32>(data1), - static_cast<OMX_U32>(data2)); - } - - case omx_message::EMPTY_BUFFER_DONE: - { - IOMX::buffer_id bufferID; - CHECK(msg->findInt32("buffer", (int32_t*)&bufferID)); - - return onOMXEmptyBufferDone(bufferID); - } - - case omx_message::FILL_BUFFER_DONE: - { - IOMX::buffer_id bufferID; - CHECK(msg->findInt32("buffer", (int32_t*)&bufferID)); - - int32_t rangeOffset, rangeLength, flags; - int64_t timeUs; - void *platformPrivate = NULL; - void *dataPtr = NULL; - - CHECK(msg->findInt32("range_offset", &rangeOffset)); - CHECK(msg->findInt32("range_length", &rangeLength)); - CHECK(msg->findInt32("flags", &flags)); - CHECK(msg->findInt64("timestamp", &timeUs)); - //CHECK(msg->findPointer("platform_private", (void **)&platformPrivate)); - //CHECK(msg->findPointer("data_ptr", (void **)&dataPtr)); - - return onOMXFillBufferDone( - bufferID, - (size_t)rangeOffset, (size_t)rangeLength, - (OMX_U32)flags, - timeUs, - platformPrivate, - dataPtr); - } - - default: - TRESPASS(); - break; - } -} - -bool DashCodec::BaseState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - if (event != OMX_EventError) { - ALOGV("[%s] EVENT(%d, 0x%08lx, 0x%08lx)", - mCodec->mComponentName.c_str(), event, data1, data2); - - return false; - } - - ALOGE("[%s] ERROR(0x%08lx)", mCodec->mComponentName.c_str(), data1); - - mCodec->signalError((OMX_ERRORTYPE)data1); - - return true; -} - -bool DashCodec::BaseState::onOMXEmptyBufferDone(IOMX::buffer_id bufferID) { - ALOGV("[%s] onOMXEmptyBufferDone %p", - mCodec->mComponentName.c_str(), bufferID); - - BufferInfo *info = - mCodec->findBufferByID(kPortIndexInput, bufferID); - - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_COMPONENT); - info->mStatus = BufferInfo::OWNED_BY_US; - - const sp<AMessage> &bufferMeta = info->mData->meta(); - void *mediaBuffer; - if (bufferMeta->findPointer("mediaBuffer", &mediaBuffer) - && mediaBuffer != NULL) { - // We're in "store-metadata-in-buffers" mode, the underlying - // OMX component had access to data that's implicitly refcounted - // by this "mediaBuffer" object. Now that the OMX component has - // told us that it's done with the input buffer, we can decrement - // the mediaBuffer's reference count. - - ALOGV("releasing mbuf %p", mediaBuffer); - - ((MediaBuffer *)mediaBuffer)->release(); - mediaBuffer = NULL; - - bufferMeta->setPointer("mediaBuffer", NULL); - } - - PortMode mode = getPortMode(kPortIndexInput); - - switch (mode) { - case KEEP_BUFFERS: - break; - - case RESUBMIT_BUFFERS: - postFillThisBuffer(info); - break; - - default: - { - CHECK_EQ((int)mode, (int)FREE_BUFFERS); - TRESPASS(); // Not currently used - break; - } - } - - return true; -} - -void DashCodec::BaseState::postFillThisBuffer(BufferInfo *info) { - if (mCodec->mPortEOS[kPortIndexInput]) { - return; - } - - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatFillThisBuffer); - notify->setInt32("buffer-id", info->mBufferID); - - info->mData->meta()->clear(); - notify->setBuffer("buffer", info->mData); - - sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, mCodec->id()); - reply->setInt32("buffer-id", info->mBufferID); - - notify->setMessage("reply", reply); - - notify->post(); - - info->mStatus = BufferInfo::OWNED_BY_UPSTREAM; -} - -void DashCodec::BaseState::onInputBufferFilled(const sp<AMessage> &msg) { - IOMX::buffer_id bufferID; - CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); - - sp<ABuffer> buffer; - int32_t err = OK; - bool eos = false; - - if (!msg->findBuffer("buffer", &buffer)) { - CHECK(msg->findInt32("err", &err)); - - ALOGV("[%s] saw error %d instead of an input buffer", - mCodec->mComponentName.c_str(), err); - - buffer.clear(); - - eos = true; - } - - int32_t tmp; - if (buffer != NULL && buffer->meta()->findInt32("eos", &tmp) && tmp) { - eos = true; - err = ERROR_END_OF_STREAM; - } - - BufferInfo *info = mCodec->findBufferByID(kPortIndexInput, bufferID); - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_UPSTREAM); - - info->mStatus = BufferInfo::OWNED_BY_US; - - PortMode mode = getPortMode(kPortIndexInput); - - switch (mode) { - case KEEP_BUFFERS: - { - if (eos) { - if (!mCodec->mPortEOS[kPortIndexInput]) { - mCodec->mPortEOS[kPortIndexInput] = true; - mCodec->mInputEOSResult = err; - } - } - break; - } - - case RESUBMIT_BUFFERS: - { - if (buffer != NULL && !mCodec->mPortEOS[kPortIndexInput]) { - int64_t timeUs; - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - - OMX_U32 flags = OMX_BUFFERFLAG_ENDOFFRAME; - - int32_t isCSD; - if (buffer->meta()->findInt32("csd", &isCSD) && isCSD != 0) { - flags |= OMX_BUFFERFLAG_CODECCONFIG; - } - - if (eos) { - flags |= OMX_BUFFERFLAG_EOS; - } - - if (buffer != info->mData) { - ALOGV("[%s] Needs to copy input data for buffer %p. (%p != %p)", - mCodec->mComponentName.c_str(), - bufferID, - buffer.get(), info->mData.get()); - - CHECK_LE(buffer->size(), info->mData->capacity()); - memcpy(info->mData->data(), buffer->data(), buffer->size()); - } - - if (flags & OMX_BUFFERFLAG_CODECCONFIG) { - ALOGV("[%s] calling emptyBuffer %p w/ codec specific data", - mCodec->mComponentName.c_str(), bufferID); - } else if (flags & OMX_BUFFERFLAG_EOS) { - ALOGV("[%s] calling emptyBuffer %p w/ EOS", - mCodec->mComponentName.c_str(), bufferID); - } else { -#if TRACK_BUFFER_TIMING - ALOGI("[%s] calling emptyBuffer %p w/ time %lld us", - mCodec->mComponentName.c_str(), bufferID, timeUs); -#else - ALOGV("[%s] calling emptyBuffer %p w/ time %lld us", - mCodec->mComponentName.c_str(), bufferID, timeUs); -#endif - } - -#if TRACK_BUFFER_TIMING - DashCodec::BufferStats stats; - stats.mEmptyBufferTimeUs = ALooper::GetNowUs(); - stats.mFillBufferDoneTimeUs = -1ll; - mCodec->mBufferStats.add(timeUs, stats); -#endif - - if (mCodec->mStoreMetaDataInOutputBuffers) { - // try to submit an output buffer for each input buffer - PortMode outputMode = getPortMode(kPortIndexOutput); - - ALOGV("MetaDataBuffersToSubmit=%u portMode=%s", - mCodec->mMetaDataBuffersToSubmit, - (outputMode == FREE_BUFFERS ? "FREE" : - outputMode == KEEP_BUFFERS ? "KEEP" : "RESUBMIT")); - if (outputMode == RESUBMIT_BUFFERS) { - CHECK_EQ(mCodec->submitOutputMetaDataBuffer(), - (status_t)OK); - } - } - - CHECK_EQ(mCodec->mOMX->emptyBuffer( - mCodec->mNode, - bufferID, - 0, - buffer->size(), - flags, - timeUs), - (status_t)OK); - - info->mStatus = BufferInfo::OWNED_BY_COMPONENT; - - if (!eos) { - getMoreInputDataIfPossible(); - } else { - ALOGV("[%s] Signalled EOS on the input port", - mCodec->mComponentName.c_str()); - - mCodec->mPortEOS[kPortIndexInput] = true; - mCodec->mInputEOSResult = err; - } - } else if (!mCodec->mPortEOS[kPortIndexInput]) { - if (err != ERROR_END_OF_STREAM) { - ALOGV("[%s] Signalling EOS on the input port " - "due to error %d", - mCodec->mComponentName.c_str(), err); - } else { - ALOGV("[%s] Signalling EOS on the input port", - mCodec->mComponentName.c_str()); - } - - if (mCodec->mStoreMetaDataInOutputBuffers) { - // try to submit an output buffer for each input buffer - PortMode outputMode = getPortMode(kPortIndexOutput); - - ALOGV("MetaDataBuffersToSubmit=%u portMode=%s", - mCodec->mMetaDataBuffersToSubmit, - (outputMode == FREE_BUFFERS ? "FREE" : - outputMode == KEEP_BUFFERS ? "KEEP" : "RESUBMIT")); - if (outputMode == RESUBMIT_BUFFERS) { - CHECK_EQ(mCodec->submitOutputMetaDataBuffer(), - (status_t)OK); - } - } - - ALOGV("[%s] calling emptyBuffer %p signalling EOS", - mCodec->mComponentName.c_str(), bufferID); - - CHECK_EQ(mCodec->mOMX->emptyBuffer( - mCodec->mNode, - bufferID, - 0, - 0, - OMX_BUFFERFLAG_EOS, - 0), - (status_t)OK); - - info->mStatus = BufferInfo::OWNED_BY_COMPONENT; - - mCodec->mPortEOS[kPortIndexInput] = true; - mCodec->mInputEOSResult = err; - } - break; - - default: - CHECK_EQ((int)mode, (int)FREE_BUFFERS); - break; - } - } -} - -void DashCodec::BaseState::getMoreInputDataIfPossible() { - if (mCodec->mPortEOS[kPortIndexInput]) { - return; - } - - BufferInfo *eligible = NULL; - - for (size_t i = 0; i < mCodec->mBuffers[kPortIndexInput].size(); ++i) { - BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(i); - -#if 0 - if (info->mStatus == BufferInfo::OWNED_BY_UPSTREAM) { - // There's already a "read" pending. - return; - } -#endif - - if (info->mStatus == BufferInfo::OWNED_BY_US) { - eligible = info; - } - } - - if (eligible == NULL) { - return; - } - - postFillThisBuffer(eligible); -} - -bool DashCodec::BaseState::onOMXFillBufferDone( - IOMX::buffer_id bufferID, - size_t rangeOffset, size_t rangeLength, - OMX_U32 flags, - int64_t timeUs, - void * /*platformPrivate*/, - void * /*dataPtr*/) { - ALOGV("[%s] onOMXFillBufferDone %p time %lld us, flags = 0x%08lx", - mCodec->mComponentName.c_str(), bufferID, timeUs, flags); - - ssize_t index; - -#if TRACK_BUFFER_TIMING - index = mCodec->mBufferStats.indexOfKey(timeUs); - if (index >= 0) { - DashCodec::BufferStats *stats = &mCodec->mBufferStats.editValueAt(index); - stats->mFillBufferDoneTimeUs = ALooper::GetNowUs(); - - ALOGI("frame PTS %lld: %lld", - timeUs, - stats->mFillBufferDoneTimeUs - stats->mEmptyBufferTimeUs); - - mCodec->mBufferStats.removeItemsAt(index); - stats = NULL; - } -#endif - - BufferInfo *info = - mCodec->findBufferByID(kPortIndexOutput, bufferID, &index); - - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_COMPONENT); - - info->mDequeuedAt = ++mCodec->mDequeueCounter; - info->mStatus = BufferInfo::OWNED_BY_US; - - PortMode mode = getPortMode(kPortIndexOutput); - - switch (mode) { - case KEEP_BUFFERS: - break; - - case RESUBMIT_BUFFERS: - { - if (rangeLength == 0 && !(flags & OMX_BUFFERFLAG_EOS)) { - ALOGV("[%s] calling fillBuffer %p", - mCodec->mComponentName.c_str(), info->mBufferID); - - CHECK_EQ(mCodec->mOMX->fillBuffer( - mCodec->mNode, info->mBufferID), - (status_t)OK); - - info->mStatus = BufferInfo::OWNED_BY_COMPONENT; - break; - } - - if (flags & OMX_BUFFERFLAG_EOS) { - ALOGE("[%s] saw output EOS", mCodec->mComponentName.c_str()); - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatEOS); - notify->setInt32("err", mCodec->mInputEOSResult); - notify->post(); - - mCodec->mPortEOS[kPortIndexOutput] = true; - break; - } - if (!mCodec->mIsEncoder && !mCodec->mSentFormat && !mCodec->mAdaptivePlayback) { - mCodec->sendFormatChange(); - } - - if (mCodec->mNativeWindow == NULL) { - info->mData->setRange(rangeOffset, rangeLength); - -#if 0 - if (IsIDR(info->mData)) { - ALOGI("IDR frame"); - } -#endif - } - - if (mCodec->mSkipCutBuffer != NULL) { - mCodec->mSkipCutBuffer->submit(info->mData); - } - info->mData->meta()->setInt64("timeUs", timeUs); - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatDrainThisBuffer); - notify->setInt32("buffer-id", info->mBufferID); - notify->setBuffer("buffer", info->mData); - notify->setInt32("flags", flags); - - if (flags & OMX_BUFFERFLAG_EXTRADATA) - { - OMX_U8* bufferHandle = NULL; - int64_t nFilledLen = 0; - int64_t nAllocLen = 0; - int64_t nStartOffset = 0; - - OMX_BUFFERHEADERTYPE *pBufHdr = (OMX_BUFFERHEADERTYPE *)bufferID; - - nStartOffset = pBufHdr->nOffset; - - if(mCodec->mStoreMetaDataInOutputBuffers) - { - VideoDecoderOutputMetaData *metaData = - reinterpret_cast<VideoDecoderOutputMetaData *>( - pBufHdr->pBuffer); - - bufferHandle = const_cast<OMX_U8*>( - reinterpret_cast<const OMX_U8*>(metaData->pHandle)); - -#ifdef BFAMILY_TARGET /* Venus macros and dynamic mode support present only for B-family targets.*/ - nFilledLen = (VENUS_Y_STRIDE(COLOR_FMT_NV12, mCodec->mCurrentWidth) - * VENUS_Y_SCANLINES(COLOR_FMT_NV12, mCodec->mCurrentHeight)) - + (VENUS_UV_STRIDE(COLOR_FMT_NV12, mCodec->mCurrentWidth) - * VENUS_UV_SCANLINES(COLOR_FMT_NV12, mCodec->mCurrentHeight)); - - nAllocLen = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, mCodec->mCurrentWidth, mCodec->mCurrentHeight); -#endif - } - else - { - bufferHandle = const_cast<OMX_U8*>( - reinterpret_cast<const OMX_U8*>(pBufHdr->pBuffer)); - - nFilledLen = pBufHdr->nFilledLen; - nAllocLen = pBufHdr->nAllocLen; - } - - ALOGV("[%s] Extradata present in decoded buffer." - "gralloc handle = %p, filled length = %llu, allocated length = %llu, start offset = %llu", - mCodec->mComponentName.c_str(), bufferHandle, nFilledLen, nAllocLen, nStartOffset); - - notify->setPointer("gralloc-handle", bufferHandle); - notify->setInt64("filled-length", nFilledLen); - notify->setInt64("alloc-length", nAllocLen); - notify->setInt64("start-offset", nStartOffset); - } - - sp<AMessage> reply = - new AMessage(kWhatOutputBufferDrained, mCodec->id()); - - if (!mCodec->mPostFormat && mCodec->mAdaptivePlayback){ - ALOGV("Resolution will change from this buffer, set a flag"); - reply->setInt32("resChange", 1); - mCodec->mPostFormat = true; - } - - reply->setInt32("buffer-id", info->mBufferID); - - notify->setMessage("reply", reply); - - notify->post(); - - info->mStatus = BufferInfo::OWNED_BY_DOWNSTREAM; - - break; - } - - default: - { - CHECK_EQ((int)mode, (int)FREE_BUFFERS); - - CHECK_EQ((status_t)OK, - mCodec->freeBuffer(kPortIndexOutput, index)); - break; - } - } - - return true; -} - -void DashCodec::BaseState::onOutputBufferDrained(const sp<AMessage> &msg) { - IOMX::buffer_id bufferID; - CHECK(msg->findInt32("buffer-id", (int32_t*)&bufferID)); - - ssize_t index; - BufferInfo *info = - mCodec->findBufferByID(kPortIndexOutput, bufferID, &index); - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_DOWNSTREAM); - if (mCodec->mAdaptivePlayback) { - int32_t resChange = 0; - if (msg->findInt32("resChange", &resChange) && resChange == 1) { - ALOGV("Resolution change is sent to native window now "); - mCodec->sendFormatChange(); - msg->setInt32("resChange", 0); - } - } - int32_t render; - if (mCodec->mNativeWindow != NULL - && msg->findInt32("render", &render) && render != 0) { - // The client wants this buffer to be rendered. - - status_t err; - if ((err = mCodec->mNativeWindow->queueBuffer( - mCodec->mNativeWindow.get(), - info->mGraphicBuffer.get(), -1)) == OK) { - info->mStatus = BufferInfo::OWNED_BY_NATIVE_WINDOW; - } else { - mCodec->signalError(OMX_ErrorUndefined, err); - info->mStatus = BufferInfo::OWNED_BY_US; - } - } else { - info->mStatus = BufferInfo::OWNED_BY_US; - } - - PortMode mode = getPortMode(kPortIndexOutput); - - switch (mode) { - case KEEP_BUFFERS: - { - // XXX fishy, revisit!!! What about the FREE_BUFFERS case below? - - if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { - // We cannot resubmit the buffer we just rendered, dequeue - // the spare instead. - - info = mCodec->dequeueBufferFromNativeWindow(); - } - break; - } - - case RESUBMIT_BUFFERS: - { - if (!mCodec->mPortEOS[kPortIndexOutput]) { - if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { - // We cannot resubmit the buffer we just rendered, dequeue - // the spare instead. - - info = mCodec->dequeueBufferFromNativeWindow(); - } - - if (info != NULL) { - ALOGV("[%s] calling fillBuffer %p", - mCodec->mComponentName.c_str(), info->mBufferID); - - CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID), - (status_t)OK); - - info->mStatus = BufferInfo::OWNED_BY_COMPONENT; - } - } - break; - } - - default: - { - CHECK_EQ((int)mode, (int)FREE_BUFFERS); - - CHECK_EQ((status_t)OK, - mCodec->freeBuffer(kPortIndexOutput, index)); - break; - } - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::UninitializedState::UninitializedState(DashCodec *codec) - : BaseState(codec) { -} - -void DashCodec::UninitializedState::stateEntered() { - ALOGV("Now uninitialized"); -} - -bool DashCodec::UninitializedState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case DashCodec::kWhatSetup: - { - onSetup(msg); - - handled = true; - break; - } - - case DashCodec::kWhatAllocateComponent: - { - onAllocateComponent(msg); - handled = true; - break; - } - - case DashCodec::kWhatShutdown: - { - int32_t keepComponentAllocated; - CHECK(msg->findInt32( - "keepComponentAllocated", &keepComponentAllocated)); - CHECK(!keepComponentAllocated); - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatShutdownCompleted); - notify->post(); - - handled = true; - break; - } - - default: - return BaseState::onMessageReceived(msg); - } - - return handled; -} - -void DashCodec::UninitializedState::onSetup( - const sp<AMessage> &msg) { - if (onAllocateComponent(msg) - && mCodec->mLoadedState->onConfigureComponent(msg)) { - mCodec->mLoadedState->onStart(); - } -} - -bool DashCodec::UninitializedState::onAllocateComponent(const sp<AMessage> &msg) { - ALOGV("onAllocateComponent"); - - CHECK(mCodec->mNode == NULL); - - OMXClient client; - CHECK_EQ(client.connect(), (status_t)OK); - - sp<IOMX> omx = client.interface(); - - Vector<OMXCodec::CodecNameAndQuirks> matchingCodecs; - - AString mime; - - AString componentName; - uint32_t quirks = 0; - if (msg->findString("componentName", &componentName)) { - ssize_t index = matchingCodecs.add(); - OMXCodec::CodecNameAndQuirks *entry = &matchingCodecs.editItemAt(index); - entry->mName = String8(componentName.c_str()); - - if (!OMXCodec::findCodecQuirks( - componentName.c_str(), &entry->mQuirks)) { - entry->mQuirks = 0; - } - } else { - CHECK(msg->findString("mime", &mime)); - - int32_t encoder; - if (!msg->findInt32("encoder", &encoder)) { - encoder = false; - } - - OMXCodec::findMatchingCodecs( - mime.c_str(), - encoder, // createEncoder - NULL, // matchComponentName - 0, // flags - &matchingCodecs); - } - - sp<CodecObserver> observer = new CodecObserver; - IOMX::node_id node = NULL; - - for (size_t matchIndex = 0; matchIndex < matchingCodecs.size(); - ++matchIndex) { - componentName = matchingCodecs.itemAt(matchIndex).mName.string(); - if (mime.compare("video/hevc") == 0) { - // for targets where there is only one decoder component, then dont look - // for hybrid solution - if ((matchingCodecs.size() > 1) && - (componentName.compare("OMX.qcom.video.decoder.hevchybrid") !=0)) { - ALOGE("Ignoring Codec Component %s for mimeTye %s", - componentName.c_str(),mime.c_str()); - continue; - } - } - quirks = matchingCodecs.itemAt(matchIndex).mQuirks; - ALOGE("using Codec Component %s for mimeTye %s",componentName.c_str(),mime.c_str()); - pid_t tid = androidGetTid(); - int prevPriority = androidGetThreadPriority(tid); - androidSetThreadPriority(tid, ANDROID_PRIORITY_FOREGROUND); - status_t err = omx->allocateNode(componentName.c_str(), observer, &node); - androidSetThreadPriority(tid, prevPriority); - - if (err == OK) { - break; - } - - node = NULL; - } - - if (node == NULL) { - if (!mime.empty()) { - ALOGE("Unable to instantiate a decoder for type '%s'.", - mime.c_str()); - } else { - ALOGE("Unable to instantiate decoder '%s'.", componentName.c_str()); - } - - mCodec->signalError(OMX_ErrorComponentNotFound); - return false; - } - - sp<AMessage> notify = new AMessage(kWhatOMXMessage, mCodec->id()); - observer->setNotificationMessage(notify); - - mCodec->mComponentName = componentName; - mCodec->mFlags = 0; - - if (componentName.endsWith(".secure")) { - mCodec->mFlags |= kFlagIsSecure; - mCodec->mFlags |= kFlagPushBlankBuffersToNativeWindowOnShutdown; - } - - mCodec->mQuirks = quirks; - mCodec->mOMX = omx; - mCodec->mNode = node; - - mCodec->mPortEOS[kPortIndexInput] = - mCodec->mPortEOS[kPortIndexOutput] = false; - - mCodec->mInputEOSResult = OK; - - { - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatComponentAllocated); - notify->setString("componentName", mCodec->mComponentName.c_str()); - notify->post(); - } - - mCodec->changeState(mCodec->mLoadedState); - - return true; -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::LoadedState::LoadedState(DashCodec *codec) - : BaseState(codec) { -} - -void DashCodec::LoadedState::stateEntered() { - ALOGV("[%s] Now Loaded", mCodec->mComponentName.c_str()); - -mCodec->mDequeueCounter = 0; - mCodec->mMetaDataBuffersToSubmit = 0; - - if (mCodec->mShutdownInProgress) { - bool keepComponentAllocated = mCodec->mKeepComponentAllocated; - - mCodec->mShutdownInProgress = false; - mCodec->mKeepComponentAllocated = false; - - onShutdown(keepComponentAllocated); - } -} - -void DashCodec::LoadedState::onShutdown(bool keepComponentAllocated) { - if (!keepComponentAllocated) { - CHECK_EQ(mCodec->mOMX->freeNode(mCodec->mNode), (status_t)OK); - - mCodec->mNativeWindow.clear(); - mCodec->mNode = NULL; - mCodec->mOMX.clear(); - mCodec->mQuirks = 0; - mCodec->mFlags = 0; - mCodec->mComponentName.clear(); - - mCodec->changeState(mCodec->mUninitializedState); - } - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatShutdownCompleted); - notify->post(); -} - -bool DashCodec::LoadedState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case DashCodec::kWhatConfigureComponent: - { - onConfigureComponent(msg); - handled = true; - break; - } - - case DashCodec::kWhatStart: - { - onStart(); - handled = true; - break; - } - - case DashCodec::kWhatShutdown: - { - int32_t keepComponentAllocated; - CHECK(msg->findInt32( - "keepComponentAllocated", &keepComponentAllocated)); - - onShutdown(keepComponentAllocated); - - handled = true; - break; - } - - default: - return BaseState::onMessageReceived(msg); - } - - return handled; -} - -bool DashCodec::LoadedState::onConfigureComponent( - const sp<AMessage> &msg) { - ALOGV("onConfigureComponent"); - - CHECK(mCodec->mNode != NULL); - - int32_t value; - - if (msg->findInt32("secure-op", &value) && (value == 1)) { - mCodec->mFlags |= kFlagIsSecureOPOnly; - } - - sp<RefBase> obj; - if (msg->findObject("native-window", &obj) - && strncmp("OMX.google.", mCodec->mComponentName.c_str(), 11)) { - sp<NativeWindowWrapper> nativeWindow( - static_cast<NativeWindowWrapper *>(obj.get())); - CHECK(nativeWindow != NULL); - mCodec->mNativeWindow = nativeWindow->getNativeWindow(); - - native_window_set_scaling_mode( - mCodec->mNativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - } - CHECK_EQ((status_t)OK, mCodec->initNativeWindow()); - - AString mime; - CHECK(msg->findString("mime", &mime)); - - status_t err = mCodec->configureCodec(mime.c_str(), msg); - - if (err != OK) { - ALOGE("[%s] configureCodec returning error %d", - mCodec->mComponentName.c_str(), err); - - mCodec->signalError(OMX_ErrorUndefined, err); - return false; - } - - { - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatComponentConfigured); - notify->post(); - } - - return true; -} - -void DashCodec::LoadedState::onStart() { - ALOGV("onStart"); - - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle), - (status_t)OK); - - mCodec->changeState(mCodec->mLoadedToIdleState); -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::LoadedToIdleState::LoadedToIdleState(DashCodec *codec) - : BaseState(codec) { -} - -void DashCodec::LoadedToIdleState::stateEntered() { - ALOGV("[%s] Now Loaded->Idle", mCodec->mComponentName.c_str()); - - status_t err; - if ((err = allocateBuffers()) != OK) { - ALOGE("Failed to allocate buffers after transitioning to IDLE state " - "(error 0x%08x)", - err); - - mCodec->signalError(OMX_ErrorUndefined, err); - - mCodec->changeState(mCodec->mLoadedState); - } -} - -status_t DashCodec::LoadedToIdleState::allocateBuffers() { - status_t err = mCodec->allocateBuffersOnPort(kPortIndexInput); - - if (err != OK) { - return err; - } - - return mCodec->allocateBuffersOnPort(kPortIndexOutput); -} - -bool DashCodec::LoadedToIdleState::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatShutdown: - { - mCodec->deferMessage(msg); - return true; - } - - default: - return BaseState::onMessageReceived(msg); - } -} - -bool DashCodec::LoadedToIdleState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet); - CHECK_EQ(data2, (OMX_U32)OMX_StateIdle); - - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandStateSet, OMX_StateExecuting), - (status_t)OK); - - mCodec->changeState(mCodec->mIdleToExecutingState); - - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::IdleToExecutingState::IdleToExecutingState(DashCodec *codec) - : BaseState(codec) { -} - -void DashCodec::IdleToExecutingState::stateEntered() { - ALOGV("[%s] Now Idle->Executing", mCodec->mComponentName.c_str()); -} - -bool DashCodec::IdleToExecutingState::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatShutdown: - { - mCodec->deferMessage(msg); - return true; - } - - default: - return BaseState::onMessageReceived(msg); - } -} - -bool DashCodec::IdleToExecutingState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet); - CHECK_EQ(data2, (OMX_U32)OMX_StateExecuting); - - mCodec->mExecutingState->resume(); - mCodec->changeState(mCodec->mExecutingState); - - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::ExecutingState::ExecutingState(DashCodec *codec) - : BaseState(codec), - mActive(false) { -} - -DashCodec::BaseState::PortMode DashCodec::ExecutingState::getPortMode( - OMX_U32 /*portIndex*/) { - return RESUBMIT_BUFFERS; -} - -void DashCodec::ExecutingState::submitOutputMetaBuffers() { - // submit as many buffers as there are input buffers with the codec - // in case we are in port reconfiguring - for (size_t i = 0; i < mCodec->mBuffers[kPortIndexInput].size(); ++i) { - BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(i); - - if (info->mStatus == BufferInfo::OWNED_BY_COMPONENT) { - if (mCodec->submitOutputMetaDataBuffer() != OK) - break; - } - } -} - -void DashCodec::ExecutingState::submitRegularOutputBuffers() { - for (size_t i = 0; i < mCodec->mBuffers[kPortIndexOutput].size(); ++i) { - BufferInfo *info = &mCodec->mBuffers[kPortIndexOutput].editItemAt(i); - - if (mCodec->mNativeWindow != NULL) { - CHECK(info->mStatus == BufferInfo::OWNED_BY_US - || info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW); - - if (info->mStatus == BufferInfo::OWNED_BY_NATIVE_WINDOW) { - continue; - } - } else { - CHECK_EQ((int)info->mStatus, (int)BufferInfo::OWNED_BY_US); - } - - ALOGV("[%s] calling fillBuffer %p", - mCodec->mComponentName.c_str(), info->mBufferID); - - CHECK_EQ(mCodec->mOMX->fillBuffer(mCodec->mNode, info->mBufferID), - (status_t)OK); - - info->mStatus = BufferInfo::OWNED_BY_COMPONENT; - } -} - -void DashCodec::ExecutingState::submitOutputBuffers() { - submitRegularOutputBuffers(); - if (mCodec->mStoreMetaDataInOutputBuffers) { - submitOutputMetaBuffers(); - } -} - -void DashCodec::ExecutingState::resume() { - if (mActive) { - ALOGV("[%s] We're already active, no need to resume.", - mCodec->mComponentName.c_str()); - - return; - } - - submitOutputBuffers(); - - // Post the first input buffer. - CHECK_GT(mCodec->mBuffers[kPortIndexInput].size(), 0u); - BufferInfo *info = &mCodec->mBuffers[kPortIndexInput].editItemAt(0); - - postFillThisBuffer(info); - - mActive = true; -} - -void DashCodec::ExecutingState::stateEntered() { - ALOGV("[%s] Now Executing", mCodec->mComponentName.c_str()); - - mCodec->processDeferredMessages(); -} - -bool DashCodec::ExecutingState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case kWhatShutdown: - { - int32_t keepComponentAllocated; - CHECK(msg->findInt32( - "keepComponentAllocated", &keepComponentAllocated)); - - mCodec->mShutdownInProgress = true; - mCodec->mKeepComponentAllocated = keepComponentAllocated; - - mActive = false; - - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandStateSet, OMX_StateIdle), - (status_t)OK); - - mCodec->changeState(mCodec->mExecutingToIdleState); - - handled = true; - break; - } - - case kWhatFlush: - { - ALOGV("[%s] ExecutingState flushing now " - "(codec owns %d/%d input, %d/%d output).", - mCodec->mComponentName.c_str(), - mCodec->countBuffersOwnedByComponent(kPortIndexInput), - mCodec->mBuffers[kPortIndexInput].size(), - mCodec->countBuffersOwnedByComponent(kPortIndexOutput), - mCodec->mBuffers[kPortIndexOutput].size()); - - mActive = false; - - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandFlush, OMX_ALL), - (status_t)OK); - - mCodec->changeState(mCodec->mFlushingState); - mCodec->clearCachedFormats(); - handled = true; - break; - } - - case kWhatResume: - { - resume(); - - handled = true; - break; - } - - case kWhatRequestIDRFrame: - { - status_t err = mCodec->requestIDRFrame(); - if (err != OK) { - ALOGW("Requesting an IDR frame failed."); - } - - handled = true; - break; - } - - default: - handled = BaseState::onMessageReceived(msg); - break; - } - - return handled; -} - -bool DashCodec::ExecutingState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventPortSettingsChanged: - { - CHECK_EQ(data1, (OMX_U32)kPortIndexOutput); - - if (data2 == 0 || data2 == OMX_IndexParamPortDefinition) { - if (mCodec->mStoreMetaDataInOutputBuffers) { - ALOGE("[%s] storeMetaDataInBuffers:Rcvd port settings changed event..disabling outputport", - mCodec->mComponentName.c_str()); -mCodec->mMetaDataBuffersToSubmit = 0; - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, - OMX_CommandPortDisable, kPortIndexOutput), - (status_t)OK); - - mCodec->freeOutputBuffersNotOwnedByComponent(); - mCodec->changeState(mCodec->mOutputPortSettingsChangedState); - }else { - ALOGV("Flush output port before disable"); - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandFlush, kPortIndexOutput), - (status_t)OK); - - mCodec->changeState(mCodec->mFlushingOutputState); - } - - } else if (data2 == OMX_IndexConfigCommonOutputCrop) { - mCodec->mSentFormat = false; - mCodec->mPostFormat = false; - mCodec->queueNextFormat(); - } else { - ALOGV("[%s] OMX_EventPortSettingsChanged 0x%08lx", - mCodec->mComponentName.c_str(), data2); - } - - return true; - } - case OMX_EventIndexsettingChanged: - { - ALOGW("[%s] Received OMX_EventIndexsettingChanged event ", mCodec->mComponentName.c_str()); - mCodec->mSentFormat = false; - return true; - } - case OMX_EventBufferFlag: - { - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::OutputPortSettingsChangedState::OutputPortSettingsChangedState( - DashCodec *codec) - : BaseState(codec) { -} - -DashCodec::BaseState::PortMode DashCodec::OutputPortSettingsChangedState::getPortMode( - OMX_U32 portIndex) { - if (portIndex == kPortIndexOutput) { - return FREE_BUFFERS; - } - - CHECK_EQ(portIndex, (OMX_U32)kPortIndexInput); - - return RESUBMIT_BUFFERS; -} - -bool DashCodec::OutputPortSettingsChangedState::onMessageReceived( - const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case kWhatFlush: - case kWhatShutdown: - case kWhatResume: - { - if (msg->what() == kWhatResume) { - ALOGV("[%s] Deferring resume", mCodec->mComponentName.c_str()); - } - - mCodec->deferMessage(msg); - handled = true; - break; - } - case kWhatWaitForPortEnable: - { - int32_t d1; - int32_t d2; - CHECK(msg->findInt32("data1", &d1)); - CHECK(msg->findInt32("data2", &d2)); - - enableOutputPort((OMX_U32)d1, (OMX_U32)d2); - - handled = true; - break; - } - default: - handled = BaseState::onMessageReceived(msg); - break; - } - - return handled; -} - -void DashCodec::OutputPortSettingsChangedState::enableOutputPort(OMX_U32 data1, OMX_U32 data2) { - if (data1 == (OMX_U32)OMX_CommandPortDisable) { - CHECK_EQ(data2, (OMX_U32)kPortIndexOutput); - - ALOGV("[%s] Output port now disabled.", - mCodec->mComponentName.c_str()); - // All buffers should get freed before sending re-enabling outport after - // portsetting change. OUT Buffers OWNED_BY_DOWNSTREAM, gets freed - // only when renderer sends buffer for rendering. - // Due to timing issue, buffers OWNED_BY_DOWNSTREAM dosent get freed - // before exectution reaches here. hence wait for all such buffers - // to get free and then proceed for enabling outport. - if(!mCodec->mBuffers[kPortIndexOutput].isEmpty()) - { - ALOGE(" Wait for outport Queue to be empty before re-enable port "); - sp<AMessage> msg = new AMessage(kWhatWaitForPortEnable, mCodec->id()); - msg->setInt32("data1", data1); - msg->setInt32("data2", data2); - msg->post(10000ll); // poll again in a 10 milli second. - return; - } - - mCodec->mDealer[kPortIndexOutput].clear(); - - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandPortEnable, kPortIndexOutput), - (status_t)OK); - - status_t err; - if ((err = mCodec->allocateBuffersOnPort(kPortIndexOutput)) != OK) { - ALOGE("Failed to allocate output port buffers after " - "port reconfiguration (error 0x%08x)", - err); - - mCodec->signalError(OMX_ErrorUndefined, err); - - // This is technically not correct, but appears to be - // the only way to free the component instance. - // Controlled transitioning from excecuting->idle - // and idle->loaded seem impossible probably because - // the output port never finishes re-enabling. - mCodec->mShutdownInProgress = true; - mCodec->mKeepComponentAllocated = false; - mCodec->changeState(mCodec->mLoadedState); - } - } - - return; -} - -void DashCodec::OutputPortSettingsChangedState::stateEntered() { - ALOGV("[%s] Now handling output port settings change", - mCodec->mComponentName.c_str()); -} - -bool DashCodec::OutputPortSettingsChangedState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - if (data1 == (OMX_U32)OMX_CommandPortDisable) { - enableOutputPort(data1, data2); - return true; - } else if (data1 == (OMX_U32)OMX_CommandPortEnable) { - CHECK_EQ(data2, (OMX_U32)kPortIndexOutput); - - mCodec->mSentFormat = false; - - ALOGV("[%s] Output port now reenabled.", - mCodec->mComponentName.c_str()); - - if (mCodec->mExecutingState->active()) { - mCodec->mExecutingState->submitOutputBuffers(); - } - - mCodec->changeState(mCodec->mExecutingState); - - return true; - } - - return false; - } - - default: - return false; - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::ExecutingToIdleState::ExecutingToIdleState(DashCodec *codec) - : BaseState(codec), - mComponentNowIdle(false) { -} - -bool DashCodec::ExecutingToIdleState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case kWhatShutdown: - { - // We're already doing that... - - handled = true; - break; - } - - default: - handled = BaseState::onMessageReceived(msg); - break; - } - - return handled; -} - -void DashCodec::ExecutingToIdleState::stateEntered() { - ALOGV("[%s] Now Executing->Idle", mCodec->mComponentName.c_str()); - - mComponentNowIdle = false; - mCodec->mSentFormat = false; -} - -bool DashCodec::ExecutingToIdleState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet); - CHECK_EQ(data2, (OMX_U32)OMX_StateIdle); - - mComponentNowIdle = true; - - changeStateIfWeOwnAllBuffers(); - - return true; - } - - case OMX_EventPortSettingsChanged: - case OMX_EventBufferFlag: - { - // We're shutting down and don't care about this anymore. - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } -} - -void DashCodec::ExecutingToIdleState::changeStateIfWeOwnAllBuffers() { - if (mComponentNowIdle && mCodec->allYourBuffersAreBelongToUs()) { - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, OMX_CommandStateSet, OMX_StateLoaded), - (status_t)OK); - - CHECK_EQ(mCodec->freeBuffersOnPort(kPortIndexInput), (status_t)OK); - CHECK_EQ(mCodec->freeBuffersOnPort(kPortIndexOutput), (status_t)OK); - - if (mCodec->mFlags & kFlagPushBlankBuffersToNativeWindowOnShutdown - && mCodec->mNativeWindow != NULL) { - // We push enough 1x1 blank buffers to ensure that one of - // them has made it to the display. This allows the OMX - // component teardown to zero out any protected buffers - // without the risk of scanning out one of those buffers. - PushBlankBuffersToNativeWindow(mCodec->mNativeWindow); - } - - mCodec->changeState(mCodec->mIdleToLoadedState); - } -} - -void DashCodec::ExecutingToIdleState::onInputBufferFilled( - const sp<AMessage> &msg) { - BaseState::onInputBufferFilled(msg); - - changeStateIfWeOwnAllBuffers(); -} - -void DashCodec::ExecutingToIdleState::onOutputBufferDrained( - const sp<AMessage> &msg) { - BaseState::onOutputBufferDrained(msg); - - changeStateIfWeOwnAllBuffers(); -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::IdleToLoadedState::IdleToLoadedState(DashCodec *codec) - : BaseState(codec) { -} - -bool DashCodec::IdleToLoadedState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case kWhatShutdown: - { - // We're already doing that... - - handled = true; - break; - } - - default: - handled = BaseState::onMessageReceived(msg); - break; - } - - return handled; -} - -void DashCodec::IdleToLoadedState::stateEntered() { - ALOGV("[%s] Now Idle->Loaded", mCodec->mComponentName.c_str()); -} - -bool DashCodec::IdleToLoadedState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - CHECK_EQ(data1, (OMX_U32)OMX_CommandStateSet); - CHECK_EQ(data2, (OMX_U32)OMX_StateLoaded); - - mCodec->changeState(mCodec->mLoadedState); - - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::FlushingState::FlushingState(DashCodec *codec) - : BaseState(codec) { -} - -void DashCodec::FlushingState::stateEntered() { - ALOGV("[%s] Now Flushing", mCodec->mComponentName.c_str()); - - mFlushComplete[kPortIndexInput] = mFlushComplete[kPortIndexOutput] = false; -} - -bool DashCodec::FlushingState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case kWhatShutdown: - { - mCodec->deferMessage(msg); - break; - } - - case kWhatFlush: - { - // We're already doing this right now. - handled = true; - break; - } - - default: - handled = BaseState::onMessageReceived(msg); - break; - } - - return handled; -} - -bool DashCodec::FlushingState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - ALOGV("[%s] FlushingState onOMXEvent(%d,%ld)", - mCodec->mComponentName.c_str(), event, data1); - - switch (event) { - case OMX_EventCmdComplete: - { - CHECK_EQ(data1, (OMX_U32)OMX_CommandFlush); - - if (data2 == kPortIndexInput || data2 == kPortIndexOutput) { - CHECK(!mFlushComplete[data2]); - mFlushComplete[data2] = true; - - if (mFlushComplete[kPortIndexInput] - && mFlushComplete[kPortIndexOutput]) { - changeStateIfWeOwnAllBuffers(); - } - } else { - CHECK_EQ(data2, OMX_ALL); - CHECK(mFlushComplete[kPortIndexInput]); - CHECK(mFlushComplete[kPortIndexOutput]); - - changeStateIfWeOwnAllBuffers(); - } - - return true; - } - - case OMX_EventPortSettingsChanged: - { - sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id()); - msg->setInt32("type", omx_message::EVENT); - msg->setInt32("node", mCodec->mNode); - msg->setInt32("event", event); - msg->setInt32("data1", data1); - msg->setInt32("data2", data2); - - ALOGV("[%s] Deferring OMX_EventPortSettingsChanged", - mCodec->mComponentName.c_str()); - - mCodec->deferMessage(msg); - - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } - - return true; -} - -void DashCodec::FlushingState::onOutputBufferDrained(const sp<AMessage> &msg) { - BaseState::onOutputBufferDrained(msg); - - changeStateIfWeOwnAllBuffers(); -} - -void DashCodec::FlushingState::onInputBufferFilled(const sp<AMessage> &msg) { - BaseState::onInputBufferFilled(msg); - - changeStateIfWeOwnAllBuffers(); -} - -void DashCodec::FlushingState::changeStateIfWeOwnAllBuffers() { - if (mFlushComplete[kPortIndexInput] - && mFlushComplete[kPortIndexOutput] - && mCodec->allYourBuffersAreBelongToUs()) { - // We now own all buffers except possibly those still queued with - // the native window for rendering. Let's get those back as well. - mCodec->waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs(); - - sp<AMessage> notify = mCodec->mNotify->dup(); - notify->setInt32("what", CodecBase::kWhatFlushCompleted); - notify->post(); - - mCodec->mPortEOS[kPortIndexInput] = - mCodec->mPortEOS[kPortIndexOutput] = false; - - mCodec->mInputEOSResult = OK; - - mCodec->changeState(mCodec->mExecutingState); - } -} - -//////////////////////////////////////////////////////////////////////////////// - -DashCodec::FlushingOutputState::FlushingOutputState(DashCodec *codec) - : BaseState(codec) { -} - -DashCodec::BaseState::PortMode DashCodec::FlushingOutputState::getPortMode(OMX_U32 portIndex) { - if (portIndex == kPortIndexOutput) - { - return KEEP_BUFFERS; - } - return RESUBMIT_BUFFERS; -} - -void DashCodec::FlushingOutputState::stateEntered() { - ALOGV("[%s] Now Flushing Output Port", mCodec->mComponentName.c_str()); - - mFlushComplete = false; -} - -bool DashCodec::FlushingOutputState::onMessageReceived(const sp<AMessage> &msg) { - bool handled = false; - - switch (msg->what()) { - case kWhatShutdown: - { - mCodec->deferMessage(msg); - handled = true; - break; - } - - case kWhatFlush: - { - ALOGV("Flush received during port reconfig, deferring it"); - mCodec->deferMessage(msg); - handled = true; - break; - } - - case kWhatInputBufferFilled: - { - mCodec->deferMessage(msg); - changeStateIfWeOwnAllBuffers(); - handled = true; - break; - } - - default: - handled = BaseState::onMessageReceived(msg); - break; - } - - return handled; -} - -bool DashCodec::FlushingOutputState::onOMXEvent( - OMX_EVENTTYPE event, OMX_U32 data1, OMX_U32 data2) { - switch (event) { - case OMX_EventCmdComplete: - { - CHECK_EQ(data1, (OMX_U32)OMX_CommandFlush); - CHECK_EQ(data2,(OMX_U32)kPortIndexOutput); - ALOGV("FlushingOutputState::onOMXEvent Output port flush complete"); - mFlushComplete = true; - changeStateIfWeOwnAllBuffers(); - return true; - } - - case OMX_EventPortSettingsChanged: - { - sp<AMessage> msg = new AMessage(kWhatOMXMessage, mCodec->id()); - msg->setInt32("type", omx_message::EVENT); - msg->setInt32("node", mCodec->mNode); - msg->setInt32("event", event); - msg->setInt32("data1", data1); - msg->setInt32("data2", data2); - - ALOGV("[%s] Deferring OMX_EventPortSettingsChanged", - mCodec->mComponentName.c_str()); - - mCodec->deferMessage(msg); - - return true; - } - - default: - return BaseState::onOMXEvent(event, data1, data2); - } - - return true; -} - -void DashCodec::FlushingOutputState::onOutputBufferDrained(const sp<AMessage> &msg) { - BaseState::onOutputBufferDrained(msg); - - changeStateIfWeOwnAllBuffers(); -} - -void DashCodec::FlushingOutputState::onInputBufferFilled(const sp<AMessage> &msg) { - BaseState::onInputBufferFilled(msg); - - changeStateIfWeOwnAllBuffers(); -} - -void DashCodec::FlushingOutputState::changeStateIfWeOwnAllBuffers() { - ALOGV("FlushingOutputState::ChangeState %d",mFlushComplete); - - if (mFlushComplete && mCodec->allYourBuffersAreBelongToUs( kPortIndexOutput )) { - ALOGV("FlushingOutputState Sending port disable "); - CHECK_EQ(mCodec->mOMX->sendCommand( - mCodec->mNode, - OMX_CommandPortDisable, kPortIndexOutput), - (status_t)OK); - - mCodec->mPortEOS[kPortIndexInput] = false; - mCodec->mPortEOS[kPortIndexOutput] = false; - - ALOGV("FlushingOutputState Calling freeOutputBuffersNotOwnedByComponent"); - mCodec->freeOutputBuffersNotOwnedByComponent(); - - ALOGV("FlushingOutputState Change state to port settings changed"); - mCodec->changeState(mCodec->mOutputPortSettingsChangedState); - } -} - -} // namespace android diff --git a/dashplayer/DashCodec.h b/dashplayer/DashCodec.h deleted file mode 100644 index 7ff5abb9..00000000 --- a/dashplayer/DashCodec.h +++ /dev/null @@ -1,313 +0,0 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * Not a Contribution, Apache license notifications and license are retained - * for attribution purposes only. - * - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DASH_CODEC_H_ -#define DASH_CODEC_H_ - -#include <stdint.h> -#include <android/native_window.h> -#include <media/IOMX.h> -#include <media/stagefright/foundation/AHierarchicalStateMachine.h> -#include <media/stagefright/CodecBase.h> -#include <media/stagefright/SkipCutBuffer.h> -#include <OMX_Audio.h> -#include <OMX_Component.h> -#include <OMX_IVCommon.h> - -#define TRACK_BUFFER_TIMING 0 - -namespace android { - -struct ABuffer; -struct MemoryDealer; - -struct DashCodec : public AHierarchicalStateMachine, public CodecBase { - DashCodec(); - - virtual void setNotificationMessage(const sp<AMessage> &msg); - - void initiateSetup(const sp<AMessage> &msg); - - virtual void initiateAllocateComponent(const sp<AMessage> &msg); - virtual void initiateConfigureComponent(const sp<AMessage> &msg); - virtual void initiateCreateInputSurface() { - return; - } - virtual void initiateStart(); - virtual void initiateShutdown(bool keepComponentAllocated = false); - - virtual void signalFlush(); - virtual void signalResume(); - - virtual void signalSetParameters(const sp<AMessage> & /*msg*/) { - return; - } - virtual void signalEndOfInputStream() { - return; - } - virtual void signalRequestIDRFrame(); - - void queueNextFormat(); - void clearCachedFormats(); - - static status_t PushBlankBuffersToNativeWindow(sp<ANativeWindow> nativeWindow); - - // AHierarchicalStateMachine implements the message handling - virtual void onMessageReceived(const sp<AMessage> &msg) { - handleMessage(msg); - } - - struct PortDescription : public CodecBase::PortDescription { - size_t countBuffers(); - IOMX::buffer_id bufferIDAt(size_t index) const; - sp<ABuffer> bufferAt(size_t index) const; - - private: - friend struct DashCodec; - - Vector<IOMX::buffer_id> mBufferIDs; - Vector<sp<ABuffer> > mBuffers; - - PortDescription(); - void addBuffer(IOMX::buffer_id id, const sp<ABuffer> &buffer); - - DISALLOW_EVIL_CONSTRUCTORS(PortDescription); - }; - -protected: - virtual ~DashCodec(); - -private: - struct BaseState; - struct UninitializedState; - struct LoadedState; - struct LoadedToIdleState; - struct IdleToExecutingState; - struct ExecutingState; - struct OutputPortSettingsChangedState; - struct ExecutingToIdleState; - struct IdleToLoadedState; - struct FlushingState; - struct FlushingOutputState; - - enum { - kWhatSetup = 'setu', - kWhatOMXMessage = 'omx ', - kWhatInputBufferFilled = 'inpF', - kWhatOutputBufferDrained = 'outD', - kWhatShutdown = 'shut', - kWhatFlush = 'flus', - kWhatResume = 'resm', - kWhatDrainDeferredMessages = 'drai', - kWhatAllocateComponent = 'allo', - kWhatConfigureComponent = 'conf', - kWhatStart = 'star', - kWhatRequestIDRFrame = 'ridr', - kWhatWaitForPortEnable = 'wfpe', - }; - - enum { - kPortIndexInput = 0, - kPortIndexOutput = 1 - }; - - enum { - kFlagIsSecure = 1, - kFlagIsSecureOPOnly = 2, - kFlagPushBlankBuffersToNativeWindowOnShutdown = 4 - }; - - struct BufferInfo { - enum Status { - OWNED_BY_US, - OWNED_BY_COMPONENT, - OWNED_BY_UPSTREAM, - OWNED_BY_DOWNSTREAM, - OWNED_BY_NATIVE_WINDOW, - }; - - IOMX::buffer_id mBufferID; - Status mStatus; - unsigned mDequeuedAt; - - sp<ABuffer> mData; - sp<GraphicBuffer> mGraphicBuffer; - }; - -#if TRACK_BUFFER_TIMING - struct BufferStats { - int64_t mEmptyBufferTimeUs; - int64_t mFillBufferDoneTimeUs; - }; - - KeyedVector<int64_t, BufferStats> mBufferStats; -#endif - - sp<AMessage> mNotify; - - sp<UninitializedState> mUninitializedState; - sp<LoadedState> mLoadedState; - sp<LoadedToIdleState> mLoadedToIdleState; - sp<IdleToExecutingState> mIdleToExecutingState; - sp<ExecutingState> mExecutingState; - sp<OutputPortSettingsChangedState> mOutputPortSettingsChangedState; - sp<ExecutingToIdleState> mExecutingToIdleState; - sp<IdleToLoadedState> mIdleToLoadedState; - sp<FlushingState> mFlushingState; - sp<FlushingOutputState> mFlushingOutputState; - sp<SkipCutBuffer> mSkipCutBuffer; - - AString mComponentName; - uint32_t mFlags; - uint32_t mQuirks; - sp<IOMX> mOMX; - IOMX::node_id mNode; - sp<MemoryDealer> mDealer[2]; - - sp<ANativeWindow> mNativeWindow; - - Vector<BufferInfo> mBuffers[2]; - bool mPortEOS[2]; - status_t mInputEOSResult; - - List<sp<AMessage> > mDeferredQueue; - - bool mSentFormat; - bool mPostFormat; - bool mIsEncoder; - - bool mShutdownInProgress; - - // If "mKeepComponentAllocated" we only transition back to Loaded state - // and do not release the component instance. - bool mKeepComponentAllocated; - - int32_t mEncoderDelay; - int32_t mEncoderPadding; - - bool mChannelMaskPresent; - int32_t mChannelMask; - unsigned mDequeueCounter; - bool mStoreMetaDataInOutputBuffers; - int32_t mMetaDataBuffersToSubmit; - - int32_t mCurrentWidth; - int32_t mCurrentHeight; - - status_t allocateBuffersOnPort(OMX_U32 portIndex); - status_t freeBuffersOnPort(OMX_U32 portIndex); - status_t freeBuffer(OMX_U32 portIndex, size_t i); - - status_t configureOutputBuffersFromNativeWindow( - OMX_U32 *nBufferCount, OMX_U32 *nBufferSize, - OMX_U32 *nMinUndequeuedBuffers); - status_t allocateOutputMetaDataBuffers(); - status_t submitOutputMetaDataBuffer(); - status_t allocateOutputBuffersFromNativeWindow(); - status_t cancelBufferToNativeWindow(BufferInfo *info); - status_t freeOutputBuffersNotOwnedByComponent(); - BufferInfo *dequeueBufferFromNativeWindow(); - - BufferInfo *findBufferByID( - uint32_t portIndex, IOMX::buffer_id bufferID, - ssize_t *index = NULL); - - status_t setComponentRole(bool isEncoder, const char *mime); - status_t configureCodec(const char *mime, const sp<AMessage> &msg); - - status_t setVideoPortFormatType( - OMX_U32 portIndex, - OMX_VIDEO_CODINGTYPE compressionFormat, - OMX_COLOR_FORMATTYPE colorFormat); - - status_t setSupportedOutputFormat(); - - status_t setupVideoDecoder( - const char *mime, int32_t width, int32_t height); - - status_t setupVideoEncoder( - const char *mime, const sp<AMessage> &msg); - - status_t setVideoFormatOnPort( - OMX_U32 portIndex, - int32_t width, int32_t height, - OMX_VIDEO_CODINGTYPE compressionFormat); - - status_t setupAACCodec( - bool encoder, - int32_t numChannels, int32_t sampleRate, int32_t bitRate, - int32_t aacProfile, bool isADTS); - - status_t selectAudioPortFormat( - OMX_U32 portIndex, OMX_AUDIO_CODINGTYPE desiredFormat); - - status_t setupAMRCodec(bool encoder, bool isWAMR, int32_t bitRate); - status_t setupG711Codec(bool encoder, int32_t numChannels); - - status_t setupFlacCodec( - bool encoder, int32_t numChannels, int32_t sampleRate, int32_t compressionLevel); - - status_t setupRawAudioFormat( - OMX_U32 portIndex, int32_t sampleRate, int32_t numChannels); - - status_t setMinBufferSize(OMX_U32 portIndex, size_t size); - - status_t setupMPEG4EncoderParameters(const sp<AMessage> &msg); - status_t setupH263EncoderParameters(const sp<AMessage> &msg); - status_t setupAVCEncoderParameters(const sp<AMessage> &msg); - - status_t verifySupportForProfileAndLevel(int32_t profile, int32_t level); - - status_t configureBitrate( - int32_t bitrate, OMX_VIDEO_CONTROLRATETYPE bitrateMode); - - status_t setupErrorCorrectionParameters(); - - status_t initNativeWindow(); - - // Returns true iff all buffers on the given port have status OWNED_BY_US. - bool allYourBuffersAreBelongToUs(OMX_U32 portIndex); - - bool allYourBuffersAreBelongToUs(); - - void waitUntilAllPossibleNativeWindowBuffersAreReturnedToUs(); - - size_t countBuffersOwnedByComponent(OMX_U32 portIndex) const; - size_t countBuffersOwnedByNativeWindow() const; - - void deferMessage(const sp<AMessage> &msg); - void processDeferredMessages(); - - void sendFormatChange(); - - void signalError( - OMX_ERRORTYPE error = OMX_ErrorUndefined, - status_t internalError = UNKNOWN_ERROR); - - status_t requestIDRFrame(); - bool mAdaptivePlayback; - Vector<OMX_PARAM_PORTDEFINITIONTYPE*> mFormats; - Vector<OMX_CONFIG_RECTTYPE*> mOutputCrops; - DISALLOW_EVIL_CONSTRUCTORS(DashCodec); -}; - -} // namespace android - -#endif // DASH_CODEC_H_ diff --git a/dashplayer/DashFactory.cpp b/dashplayer/DashFactory.cpp deleted file mode 100644 index c77d1e1e..00000000 --- a/dashplayer/DashFactory.cpp +++ /dev/null @@ -1,60 +0,0 @@ -/* - *Copyright (c) 2013, The Linux Foundation. All rights reserved. - *Not a Contribution, Apache license notifications and license are retained - *for attribution purposes only. - * - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "DASHFactory" -#include <media/IMediaPlayer.h> -#include "DashPlayerDriver.h" -#include "MediaPlayerFactory.h" - -namespace android { - -class DashPlayerFactory : public MediaPlayerFactory::IFactory { - public: - virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, - const char* url, - float /*curScore*/) { - if (!strncasecmp("http://", url, 7)) { - size_t len = strlen(url); - if (len >= 5 && !strcasecmp(".mpd", &url[len - 4])) { - ALOGI("Using DashPlayer for .mpd"); - return 1.0; - } - } - return 0.0; - } - - virtual float scoreFactory(const sp<IMediaPlayer>& /*client*/, - const sp<IStreamSource> & /*source*/, - float /*curScore*/) { - return 0.0; - } - - virtual sp<MediaPlayerBase> createPlayer(pid_t /*pid*/) { - return new DashPlayerDriver; - } -}; - -extern "C" MediaPlayerFactory::IFactory* CreateDASHFactory() -{ - return new DashPlayerFactory(); -} - -} // namespace android diff --git a/dashplayer/DashPacketSource.cpp b/dashplayer/DashPacketSource.cpp deleted file mode 100644 index 7f31daad..00000000 --- a/dashplayer/DashPacketSource.cpp +++ /dev/null @@ -1,265 +0,0 @@ -/* - *Copyright (c) 2013, The Linux Foundation. All rights reserved. - *Not a Contribution, Apache license notifications and license are retained - *for attribution purposes only. - *Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "DashPacketSource.h" -#include "DashPlayer.h" -#include <media/stagefright/MediaBuffer.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MetaData.h> -#include <utils/Vector.h> -#include <cutils/properties.h> - -#define DPS_MSG_ERROR(...) ALOGE(__VA_ARGS__) -#define DPS_MSG_HIGH(...) if(mLogLevel >= 1){ALOGE(__VA_ARGS__);} -#define DPS_MSG_MEDIUM(...) if(mLogLevel >= 2){ALOGE(__VA_ARGS__);} -#define DPS_MSG_LOW(...) if(mLogLevel >= 3){ALOGE(__VA_ARGS__);} - -namespace android { - -DashPacketSource::DashPacketSource(const sp<MetaData> &meta) - : mIsAudio(false), - mFormat(meta), - mEOSResult(OK), - mLogLevel(0) { - - char property_value[PROPERTY_VALUE_MAX] = {0}; - property_get("persist.dash.debug.level", property_value, NULL); - if(*property_value) { - mLogLevel = atoi(property_value); - } - - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - if (!strncasecmp("audio/", mime, 6)) { - mIsAudio = true; - } -} - -void DashPacketSource::setFormat(const sp<MetaData> &meta) { - Mutex::Autolock autoLock(mLock); - CHECK(mFormat == NULL); - mFormat = meta; -} - -void DashPacketSource::updateFormat(const sp<MetaData> &meta) { - Mutex::Autolock autoLock(mLock); - mFormat = meta; -} - -DashPacketSource::~DashPacketSource() { -} - -status_t DashPacketSource::start(MetaData * /*params*/) { - return OK; -} - -status_t DashPacketSource::stop() { - return OK; -} - -sp<MetaData> DashPacketSource::getFormat() { - Mutex::Autolock autoLock(mLock); - return mFormat; -} - -status_t DashPacketSource::dequeueAccessUnit(sp<ABuffer> *buffer) { - buffer->clear(); - - Mutex::Autolock autoLock(mLock); - while (mEOSResult == OK && mBuffers.empty()) { - mCondition.wait(mLock); - } - - if (!mBuffers.empty()) { - *buffer = *mBuffers.begin(); - mBuffers.erase(mBuffers.begin()); - - int32_t discontinuity; - if ((*buffer)->meta()->findInt32("discontinuity", &discontinuity)) { - if (wasFormatChange(discontinuity)) { - mFormat.clear(); - } - - return INFO_DISCONTINUITY; - } - - return OK; - } - - return mEOSResult; -} - -status_t DashPacketSource::read( - MediaBuffer **out, const ReadOptions *) { - *out = NULL; - - Mutex::Autolock autoLock(mLock); - while (mEOSResult == OK && mBuffers.empty()) { - mCondition.wait(mLock); - } - - if (!mBuffers.empty()) { - const sp<ABuffer> buffer = *mBuffers.begin(); - mBuffers.erase(mBuffers.begin()); - - int32_t discontinuity; - if (buffer->meta()->findInt32("discontinuity", &discontinuity)) { - if (wasFormatChange(discontinuity)) { - mFormat.clear(); - } - - return INFO_DISCONTINUITY; - } else { - int64_t timeUs; - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - - MediaBuffer *mediaBuffer = new MediaBuffer(buffer); - - mediaBuffer->meta_data()->setInt64(kKeyTime, timeUs); - - *out = mediaBuffer; - return OK; - } - } - - return mEOSResult; -} - -bool DashPacketSource::wasFormatChange( - int32_t discontinuityType) const { - if (mIsAudio) { - return (discontinuityType & ATSParser::DISCONTINUITY_AUDIO_FORMAT) != 0; - } - - return (discontinuityType & ATSParser::DISCONTINUITY_VIDEO_FORMAT) != 0; -} - -void DashPacketSource::queueAccessUnit(const sp<ABuffer> &buffer) { - int32_t damaged; - if (buffer->meta()->findInt32("damaged", &damaged) && damaged) { - // LOG(VERBOSE) << "discarding damaged AU"; - return; - } - - int64_t timeUs; - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - DPS_MSG_LOW("queueAccessUnit timeUs=%lld us (%.2f secs)", timeUs, (double)timeUs / 1E6); - - Mutex::Autolock autoLock(mLock); - mBuffers.push_back(buffer); - DPS_MSG_LOW("@@@@:: DashPacketSource --> size is %d ",mBuffers.size() ); - mCondition.signal(); -} - -int DashPacketSource::getQueueSize() { - return (int)mBuffers.size(); -} - -void DashPacketSource::queueDiscontinuity( - ATSParser::DiscontinuityType type, - const sp<AMessage> &extra) { - Mutex::Autolock autoLock(mLock); - - if (type == ATSParser::DISCONTINUITY_TIME) { - DPS_MSG_HIGH("Flushing all Access units for seek"); - mBuffers.clear(); - mEOSResult = OK; - mCondition.signal(); - return; - } - - mEOSResult = OK; - - sp<ABuffer> buffer = new ABuffer(0); - buffer->meta()->setInt32("discontinuity", static_cast<int32_t>(type)); - buffer->meta()->setMessage("extra", extra); - - mBuffers.push_back(buffer); - mCondition.signal(); -} - -void DashPacketSource::signalEOS(status_t result) { - CHECK(result != OK); - - Mutex::Autolock autoLock(mLock); - mEOSResult = result; - mCondition.signal(); -} - -bool DashPacketSource::hasBufferAvailable(status_t *finalResult) { - Mutex::Autolock autoLock(mLock); - if (!mBuffers.empty()) { - return true; - } - - *finalResult = mEOSResult; - return false; -} - -int64_t DashPacketSource::getBufferedDurationUs(status_t *finalResult) { - Mutex::Autolock autoLock(mLock); - - *finalResult = mEOSResult; - - if (mBuffers.empty()) { - return 0; - } - - int64_t time1 = -1; - int64_t time2 = -1; - - List<sp<ABuffer> >::iterator it = mBuffers.begin(); - while (it != mBuffers.end()) { - const sp<ABuffer> &buffer = *it; - - int64_t timeUs; - if (buffer->meta()->findInt64("timeUs", &timeUs)) { - if (time1 < 0) { - time1 = timeUs; - } - - time2 = timeUs; - } else { - // This is a discontinuity, reset everything. - time1 = time2 = -1; - } - - ++it; - } - - return time2 - time1; -} - -status_t DashPacketSource::nextBufferTime(int64_t *timeUs) { - *timeUs = 0; - - Mutex::Autolock autoLock(mLock); - - if (mBuffers.empty()) { - return mEOSResult != OK ? mEOSResult : -EWOULDBLOCK; - } - - sp<ABuffer> buffer = *mBuffers.begin(); - CHECK(buffer->meta()->findInt64("timeUs", timeUs)); - return OK; -} - - -} // namespace android diff --git a/dashplayer/DashPacketSource.h b/dashplayer/DashPacketSource.h deleted file mode 100644 index dbf3ca99..00000000 --- a/dashplayer/DashPacketSource.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - *Copyright (c) 2013, The Linux Foundation. All rights reserved. - *Not a Contribution, Apache license notifications and license are retained - *for attribution purposes only. - *Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DASH_PACKET_SOURCE_H_ - -#define DASH_PACKET_SOURCE_H_ - -#include <media/stagefright/foundation/ABase.h> -#include <media/stagefright/MediaSource.h> -#include <utils/threads.h> -#include <utils/List.h> -#include "ATSParser.h" - -namespace android { - -struct ABuffer; - -struct DashPacketSource : public MediaSource { - DashPacketSource(const sp<MetaData> &meta); - - void setFormat(const sp<MetaData> &meta); - - virtual status_t start(MetaData *params = NULL); - virtual status_t stop(); - virtual sp<MetaData> getFormat(); - - virtual status_t read( - MediaBuffer **buffer, const ReadOptions *options = NULL); - - bool hasBufferAvailable(status_t *finalResult); - - // Returns the difference between the last and the first queued - // presentation timestamps since the last discontinuity (if any). - int64_t getBufferedDurationUs(status_t *finalResult); - - status_t nextBufferTime(int64_t *timeUs); - - void queueAccessUnit(const sp<ABuffer> &buffer); - - void queueDiscontinuity( - ATSParser::DiscontinuityType type, const sp<AMessage> &extra); - - void signalEOS(status_t result); - - status_t dequeueAccessUnit(sp<ABuffer> *buffer); - void updateFormat(const sp<MetaData> &meta); - int getQueueSize(); - - -protected: - virtual ~DashPacketSource(); - -private: - Mutex mLock; - Condition mCondition; - - bool mIsAudio; - sp<MetaData> mFormat; - List<sp<ABuffer> > mBuffers; - status_t mEOSResult; - int mLogLevel; - - bool wasFormatChange(int32_t discontinuityType) const; - - DISALLOW_EVIL_CONSTRUCTORS(DashPacketSource); -}; - - -} // namespace android - -#endif // DASH_PACKET_SOURCE_H_ diff --git a/dashplayer/DashPlayer.cpp b/dashplayer/DashPlayer.cpp deleted file mode 100644 index 77d57a28..00000000 --- a/dashplayer/DashPlayer.cpp +++ /dev/null @@ -1,2523 +0,0 @@ -/* - *Copyright (c) 2013 - 2014, The Linux Foundation. All rights reserved. - *Not a Contribution, Apache license notifications and license are retained - *for attribution purposes only. - * - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 - -#define LOG_TAG "DashPlayer" -#define SRMax 30 -#include <utils/Log.h> -#include <dlfcn.h> // for dlopen/dlclose -#include "DashPlayer.h" -#include "DashPlayerDecoder.h" -#include "DashPlayerDriver.h" -#include "DashPlayerRenderer.h" -#include "DashPlayerSource.h" -#include "ATSParser.h" -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> -#include <gui/IGraphicBufferProducer.h> -#include "avc_utils.h" -#include "OMX_QCOMExtns.h" -#include <gralloc_priv.h> -#include <cutils/properties.h> -#include <utils/Log.h> -#include <media/msm_media_info.h> -#include <qcmediaplayer.h> - -#define DP_MSG_ERROR(...) ALOGE(__VA_ARGS__) -#define DP_MSG_HIGH(...) if(mLogLevel >= 1){ALOGE(__VA_ARGS__);} -#define DP_MSG_MEDIUM(...) if(mLogLevel >= 2){ALOGE(__VA_ARGS__);} -#define DP_MSG_LOW(...) if(mLogLevel >= 3){ALOGE(__VA_ARGS__);} - -namespace android { - -struct DashPlayer::Action : public RefBase { - Action() {} - - virtual void execute(DashPlayer *player) = 0; - -private: - DISALLOW_EVIL_CONSTRUCTORS(Action); -}; - -struct DashPlayer::SetSurfaceAction : public Action { - SetSurfaceAction(const sp<Surface> &wrapper) - : mWrapper(wrapper) { - } - - virtual void execute(DashPlayer *player) { - player->performSetSurface(mWrapper); - } - -private: - sp<Surface> mWrapper; - - DISALLOW_EVIL_CONSTRUCTORS(SetSurfaceAction); -}; - -struct DashPlayer::ShutdownDecoderAction : public Action { - ShutdownDecoderAction(bool audio, bool video) - : mAudio(audio), - mVideo(video) { - } - - virtual void execute(DashPlayer *player) { - player->performDecoderShutdown(mAudio, mVideo); - } - -private: - bool mAudio; - bool mVideo; - - DISALLOW_EVIL_CONSTRUCTORS(ShutdownDecoderAction); -}; - -// Use this if there's no state necessary to save in order to execute -// the action. -struct DashPlayer::SimpleAction : public Action { - typedef void (DashPlayer::*ActionFunc)(); - - SimpleAction(ActionFunc func) - : mFunc(func) { - } - - virtual void execute(DashPlayer *player) { - (player->*mFunc)(); - } - -private: - ActionFunc mFunc; - - DISALLOW_EVIL_CONSTRUCTORS(SimpleAction); -}; - -//////////////////////////////////////////////////////////////////////////////// - -DashPlayer::DashPlayer() - : mUIDValid(false), - mVideoIsAVC(false), - mRenderer(NULL), - mAudioEOS(false), - mVideoEOS(false), - mScanSourcesPending(false), - isSetSurfaceTexturePending(false), - mScanSourcesGeneration(0), - mBufferingNotification(false), - mTimeDiscontinuityPending(false), - mFlushingAudio(NONE), - mFlushingVideo(NONE), - mResetInProgress(false), - mResetPostponed(false), - mSetVideoSize(true), - mSkipRenderingAudioUntilMediaTimeUs(-1ll), - mSkipRenderingVideoUntilMediaTimeUs(-1ll), - mVideoLateByUs(0ll), - mPauseIndication(false), - mSRid(0), - mStats(NULL), - mLogLevel(0), - mTimedTextCEAPresent(false), - mTimedTextCEASamplesDisc(false), - mQCTimedTextListenerPresent(false), - mCurrentWidth(0), - mCurrentHeight(0), - mColorFormat(0){ - mTrackName = new char[6]; - - char property_value[PROPERTY_VALUE_MAX] = {0}; - property_get("persist.dash.debug.level", property_value, NULL); - - if(*property_value) { - mLogLevel = atoi(property_value); - } - -} - -DashPlayer::~DashPlayer() { - if (mRenderer != NULL) { - looper()->unregisterHandler(mRenderer->id()); - } - if (mAudioDecoder != NULL) { - looper()->unregisterHandler(mAudioDecoder->id()); - } - if (mVideoDecoder != NULL) { - looper()->unregisterHandler(mVideoDecoder->id()); - } - if (mTextDecoder != NULL) { - looper()->unregisterHandler(mTextDecoder->id()); - } - if(mStats != NULL) { - mStats->logFpsSummary(); - mStats = NULL; - } - if (mTrackName != NULL) { - delete[] mTrackName; - mTrackName = NULL; - } -} - -void DashPlayer::setUID(uid_t uid) { - mUIDValid = true; - mUID = uid; -} - -void DashPlayer::setDriver(const wp<DashPlayerDriver> &driver) { - mDriver = driver; -} - -void DashPlayer::setDataSource(const sp<IStreamSource> &/*source*/) { - DP_MSG_ERROR("DashPlayer::setDataSource not Implemented..."); -} - -status_t DashPlayer::setDataSource( - const char *url, const KeyedVector<String8, String8> *headers) { - sp<AMessage> msg = new AMessage(kWhatSetDataSource, this); - - sp<Source> source; - if (!strncasecmp(url, "http://", 7) && - (strlen(url) >= 4 && !strcasecmp(".mpd", &url[strlen(url) - 4]))) { - /* Load the DASH HTTP Live source librery here */ - DP_MSG_LOW("DashPlayer setDataSource url sting %s",url); - source = LoadCreateSource(url, headers, mUIDValid, mUID); - if (source != NULL) { - msg->setObject("source", source); - msg->post(); - return OK; - } else { - DP_MSG_ERROR("Error creating DASH source"); - return UNKNOWN_ERROR; - } - } - else - { - DP_MSG_ERROR("Unsupported URL"); - return UNKNOWN_ERROR; - } -} - -void DashPlayer::setDataSource(int /*fd*/, int64_t /*offset*/, int64_t /*length*/) { - DP_MSG_ERROR("DashPlayer::setDataSource not Implemented..."); -} - -void DashPlayer::setVideoSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer) { - sp<AMessage> msg = new AMessage(kWhatSetVideoNativeWindow, this); - - if (bufferProducer == NULL) { - msg->setObject("surface", NULL); - DP_MSG_ERROR("DashPlayer::setVideoSurfaceTexture bufferproducer = NULL "); - } else { - DP_MSG_ERROR("DashPlayer::setVideoSurfaceTexture bufferproducer = %p", bufferProducer.get()); - msg->setObject( - "surface", new Surface(bufferProducer, true /* controlledByApp */)); - } - - msg->post(); -} - -void DashPlayer::setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink) { - sp<AMessage> msg = new AMessage(kWhatSetAudioSink, this); - msg->setObject("sink", sink); - msg->post(); -} - -void DashPlayer::start() { - (new AMessage(kWhatStart, this))->post(); -} - -void DashPlayer::pause() { - (new AMessage(kWhatPause, this))->post(); -} - -void DashPlayer::resume() { - (new AMessage(kWhatResume, this))->post(); -} - -void DashPlayer::resetAsync() { - (new AMessage(kWhatReset, this))->post(); -} - -void DashPlayer::seekToAsync(int64_t seekTimeUs) { - sp<AMessage> msg = new AMessage(kWhatSeek, this); - msg->setInt64("seekTimeUs", seekTimeUs); - msg->post(); -} - -// static -bool DashPlayer::IsFlushingState(FlushStatus state, bool *needShutdown) { - switch (state) { - case FLUSHING_DECODER: - if (needShutdown != NULL) { - *needShutdown = false; - } - return true; - - case FLUSHING_DECODER_SHUTDOWN: - case SHUTTING_DOWN_DECODER: - if (needShutdown != NULL) { - *needShutdown = true; - } - return true; - - default: - return false; - } -} - -void DashPlayer::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatSetDataSource: - { - DP_MSG_ERROR("kWhatSetDataSource"); - - CHECK(mSource == NULL); - - sp<RefBase> obj; - CHECK(msg->findObject("source", &obj)); - - mSource = static_cast<Source *>(obj.get()); - prepareSource(); - - break; - } - - case kWhatSetVideoNativeWindow: - { - /* if MediaPlayer calls setDisplay(NULL) in the middle of the playback, */ - /* block this call to perform following sequence on video decoder */ - /* flush-->shutdown-->then update nativewindow to NULL */ - - /* Mediaplayer can also call valid native window to enable video */ - /* playback again dynamically, in such case scan sources will trigger */ - /* reinstantiation of video decoder and video playback continues. */ - /* TODO: Dynamic disible and reenable of video also requies support */ - /* from dash source. */ - DP_MSG_ERROR("kWhatSetVideoNativeWindow"); - -/* - if existing instance mNativeWindow=NULL, just set mNativeWindow to the new value passed - postScanSources() called below to handle use case - - Initial valid nativewindow - - first call from app to set nativewindow to null but mVideoDecoder exists. So scansources loop will not be running - - second call to set nativewindow to valid object. Enters below if() portion. Need to trigger scansources to instatiate mVideoDecoder - */ - if(mNativeWindow == NULL) - { - sp<RefBase> obj; - CHECK(msg->findObject("surface", &obj)); - - mNativeWindow = static_cast<Surface *>(obj.get()); - DP_MSG_ERROR("kWhatSetVideoNativeWindow valid nativewindow %p", mNativeWindow.get()); - if (mDriver != NULL) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - driver->notifySetSurfaceComplete(); - } - } - - DP_MSG_ERROR("kWhatSetVideoNativeWindow nativewindow %d", mScanSourcesPending); - postScanSources(); - break; - } - - /* Already existing valid mNativeWindow and valid mVideoDecoder - - Perform shutdown sequence - - postScanSources() to instantiate mVideoDecoder with the new native window object. - If no mVideoDecoder existed, and new nativewindow set to NULL push blank buffers to native window (embms audio only switch use case) - */ - - sp<RefBase> obj; - CHECK(msg->findObject("surface", &obj)); - - if(mVideoDecoder == NULL && obj.get() == NULL) - { - ANativeWindow *nativeWindow = mNativeWindow.get(); - PushBlankBuffersToNativeWindow(nativeWindow); - } - - mDeferredActions.push_back(new ShutdownDecoderAction( - false /* audio */, true /* video */)); - - DP_MSG_ERROR("kWhatSetVideoNativeWindow old nativewindow %p", mNativeWindow.get()); - DP_MSG_ERROR("kWhatSetVideoNativeWindow new nativewindow %p", obj.get()); - - mDeferredActions.push_back( - new SetSurfaceAction(static_cast<Surface *>(obj.get()))); - - if (obj.get() != NULL) { - // If there is a new surface texture, instantiate decoders - // again if possible. - mDeferredActions.push_back( - new SimpleAction(&DashPlayer::performScanSources)); - } - - isSetSurfaceTexturePending = true; - processDeferredActions(); - break; - } - - case kWhatSetAudioSink: - { - DP_MSG_ERROR("kWhatSetAudioSink"); - - sp<RefBase> obj; - CHECK(msg->findObject("sink", &obj)); - - mAudioSink = static_cast<MediaPlayerBase::AudioSink *>(obj.get()); - break; - } - - case kWhatStart: - { - DP_MSG_ERROR("kWhatStart"); - - mVideoIsAVC = false; - mAudioEOS = false; - mVideoEOS = false; - mSkipRenderingAudioUntilMediaTimeUs = -1; - mSkipRenderingVideoUntilMediaTimeUs = -1; - mVideoLateByUs = 0; - if (mSource != NULL) - { - mSource->start(); - } - - mRenderer = new Renderer( - mAudioSink, - new AMessage(kWhatRendererNotify, this)); - // for qualcomm statistics profiling - mStats = new DashPlayerStats(); - mRenderer->registerStats(mStats); - looper()->registerHandler(mRenderer); - - postScanSources(); - break; - } - - case kWhatScanSources: - { - if (!mPauseIndication) { - int32_t generation = 0; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mScanSourcesGeneration) { - // Drop obsolete msg. - break; - } - - mScanSourcesPending = false; - - //Exit scanSources if source was destroyed - //Later after source gets recreated and started (setDataSource() and start()) scanSources is posted again - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit scanSources\n"); - break; - } - - DP_MSG_LOW("scanning sources haveAudio=%d, haveVideo=%d haveText=%d", - mAudioDecoder != NULL, mVideoDecoder != NULL, mTextDecoder!= NULL); - - - if(mNativeWindow != NULL) { - instantiateDecoder(kVideo, &mVideoDecoder); - } - - if (mAudioSink != NULL) { - instantiateDecoder(kAudio, &mAudioDecoder); - } - - instantiateDecoder(kText, &mTextDecoder); - - status_t err; - if ((err = mSource->feedMoreTSData()) != OK) { - if (mAudioDecoder == NULL && mVideoDecoder == NULL) { - // We're not currently decoding anything (no audio or - // video tracks found) and we just ran out of input data. - - if (err == ERROR_END_OF_STREAM) { - notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); - } else { - notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); - } - } - break; - } - if ((mAudioDecoder == NULL && mAudioSink != NULL) || - (mVideoDecoder == NULL && mNativeWindow != NULL) || - (mTextDecoder == NULL)) { - msg->post(100000ll); - mScanSourcesPending = true; - } - - if (mTimeDiscontinuityPending && mRenderer != NULL){ - mRenderer->signalTimeDiscontinuity(); - mTimeDiscontinuityPending = false; - } - } - break; - } - - case kWhatVideoNotify: - case kWhatAudioNotify: - case kWhatTextNotify: - { - int track = -1; - if (msg->what() == kWhatAudioNotify) - track = kAudio; - else if (msg->what() == kWhatVideoNotify) - track = kVideo; - else if (msg->what() == kWhatTextNotify) - track = kText; - - getTrackName(track,mTrackName); - - int32_t what; - - if(track == kText) - { - sp<AMessage> codecRequest; - CHECK(msg->findMessage("codec-request", &codecRequest)); - - CHECK(codecRequest->findInt32("what", &what)); - } - else - { - CHECK(msg->findInt32("what", &what)); - } - - if (what == Decoder::kWhatFillThisBuffer) { - DP_MSG_LOW("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++ (%s) kWhatFillThisBuffer",mTrackName); - if ( (track == kText) && (mTextDecoder == NULL)) { - break; // no need to proceed further - } - - status_t err = feedDecoderInputData( - track, msg); - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit Notify\n"); - break; - } - - if (err == -EWOULDBLOCK) { - status_t nRet = mSource->feedMoreTSData(); - if (nRet == OK) { - msg->post(10000ll); - } - else if(nRet == (status_t)UNKNOWN_ERROR || - nRet == (status_t)ERROR_DRM_CANNOT_HANDLE) { - // reply back to codec if there is an error - DP_MSG_ERROR("FeedMoreTSData error on track %d ",track); - if (track == kText) { - sendTextPacket(NULL, (status_t)UNKNOWN_ERROR); - } else { - sp<AMessage> reply; - CHECK(msg->findMessage("reply", &reply)); - reply->setInt32("err", (status_t)UNKNOWN_ERROR); - reply->post(); - } - } - } - - } else if (what == Decoder::kWhatEOS) { - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatEOS"); - int32_t err; - CHECK(msg->findInt32("err", &err)); - - if (err == ERROR_END_OF_STREAM) { - DP_MSG_HIGH("got %s decoder EOS", mTrackName); - } else { - DP_MSG_ERROR("got %s decoder EOS w/ error %d", - mTrackName, - err); - } - - if(track == kVideo && mTimedTextCEAPresent) - { - sendTextPacket(NULL, ERROR_END_OF_STREAM, TIMED_TEXT_CEA); - } - - if(mRenderer != NULL) - { - if((track == kAudio && !IsFlushingState(mFlushingAudio)) || (track == kVideo && !IsFlushingState(mFlushingVideo))) { - mRenderer->queueEOS(track, err); - } - else{ - DP_MSG_ERROR("FlushingState for %s. Decoder EOS not queued to renderer", mTrackName); - } - } - } else if (what == Decoder::kWhatFlushCompleted) { - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatFlushCompleted"); - - Mutex::Autolock autoLock(mLock); - bool needShutdown = false; - - if (track == kAudio) { - if(IsFlushingState(mFlushingAudio, &needShutdown)) { - mFlushingAudio = FLUSHED; - } - } else if (track == kVideo){ - if(IsFlushingState(mFlushingVideo, &needShutdown)) { - mFlushingVideo = FLUSHED; - } - - mVideoLateByUs = 0; - } - - DP_MSG_MEDIUM("decoder %s flush completed", mTrackName); - - if (needShutdown) { - DP_MSG_HIGH("initiating %s decoder shutdown", - mTrackName); - - if (track == kAudio) { - mAudioDecoder->initiateShutdown(); - mFlushingAudio = SHUTTING_DOWN_DECODER; - } else if (track == kVideo) { - mVideoDecoder->initiateShutdown(); - mFlushingVideo = SHUTTING_DOWN_DECODER; - } - } - - finishFlushIfPossible(); - } else if (what == Decoder::kWhatOutputFormatChanged) { - sp<AMessage> format; - CHECK(msg->findMessage("format", &format)); - - if (track == kAudio) { - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatOutputFormatChanged:: audio"); - int32_t numChannels; - CHECK(format->findInt32("channel-count", &numChannels)); - - int32_t sampleRate; - CHECK(format->findInt32("sample-rate", &sampleRate)); - - DP_MSG_HIGH("Audio output format changed to %d Hz, %d channels", - sampleRate, numChannels); - if (mAudioSink != NULL) - { - mAudioSink->close(); - } - - audio_output_flags_t flags; - int64_t durationUs; - // FIXME: we should handle the case where the video decoder is created after - // we receive the format change indication. Current code will just make that - // we select deep buffer with video which should not be a problem as it should - // not prevent from keeping A/V sync. - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit outputFormatChanged\n"); - break; - } - if (mVideoDecoder == NULL && - mSource->getDuration(&durationUs) == OK && - durationUs > AUDIO_SINK_MIN_DEEP_BUFFER_DURATION_US) { - flags = AUDIO_OUTPUT_FLAG_DEEP_BUFFER; - } else { - flags = AUDIO_OUTPUT_FLAG_NONE; - } - - int32_t channelMask; - if (!format->findInt32("channel-mask", &channelMask)) { - channelMask = CHANNEL_MASK_USE_CHANNEL_ORDER; - } - - CHECK_EQ(mAudioSink->open( - sampleRate, - numChannels, - (audio_channel_mask_t)channelMask, - AUDIO_FORMAT_PCM_16_BIT, - 8 /* bufferCount */, - NULL, - NULL, - flags), - (status_t)OK); - mAudioSink->start(); - - if(mRenderer != NULL) { - mRenderer->signalAudioSinkChanged(); - } - } else if (track == kVideo) { - // video - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatOutputFormatChanged:: video"); - - sp<AMessage> format; - CHECK(msg->findMessage("format", &format)); - CHECK(format->findInt32("width", &mCurrentWidth)); - CHECK(format->findInt32("height", &mCurrentHeight)); - CHECK(format->findInt32("color-format", &mColorFormat)); - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatOutputFormatChanged:: video new height:%d width%d", mCurrentWidth, mCurrentHeight); - } - } else if (what == Decoder::kWhatShutdownCompleted) { - DP_MSG_ERROR("%s shutdown completed", mTrackName); - - if((track == kAudio && mFlushingAudio == SHUT_DOWN) - || (track == kVideo && mFlushingVideo == SHUT_DOWN)) - { - return; - } - - if (track == kAudio) { - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatShutdownCompleted:: audio"); - if (mAudioDecoder != NULL) { - looper()->unregisterHandler(mAudioDecoder->id()); - } - mAudioDecoder.clear(); - - mFlushingAudio = SHUT_DOWN; - } else if (track == kVideo) { - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ kWhatShutdownCompleted:: Video"); - if (mVideoDecoder != NULL) { - looper()->unregisterHandler(mVideoDecoder->id()); - } - mVideoDecoder.clear(); - - mFlushingVideo = SHUT_DOWN; - } - - finishFlushIfPossible(); - } else if (what == Decoder::kWhatError) { - DP_MSG_ERROR("Received error from %s decoder, aborting playback.", - mTrackName); - - if(track == kVideo && mTimedTextCEAPresent) - { - sendTextPacket(NULL, (status_t)UNKNOWN_ERROR, TIMED_TEXT_CEA); - } - - if(mRenderer != NULL) - { - if((track == kAudio && !IsFlushingState(mFlushingAudio)) || - (track == kVideo && !IsFlushingState(mFlushingVideo))) - { - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ Codec::kWhatError:: %s",track == kAudio ? "audio" : "video"); - mRenderer->queueEOS(track, (status_t)UNKNOWN_ERROR); - } - else{ - DP_MSG_ERROR("EOS not queued for %d track", track); - } - } - } else if (what == Decoder::kWhatDrainThisBuffer) { - if(track == kAudio || track == kVideo) { - DP_MSG_LOW("@@@@:: Dashplayer :: MESSAGE FROM CODEC +++++++++++++++++++++++++++++++ Codec::kWhatRenderBuffer:: %s",track == kAudio ? "audio" : "video"); - renderBuffer(track, msg); - } - } else { - DP_MSG_LOW("Unhandled codec notification %d.", what); - } - - break; - } - - case kWhatRendererNotify: - { - int32_t what; - CHECK(msg->findInt32("what", &what)); - - if (what == Renderer::kWhatEOS) { - int32_t audio; - CHECK(msg->findInt32("audio", &audio)); - - int32_t finalResult; - CHECK(msg->findInt32("finalResult", &finalResult)); - DP_MSG_LOW("@@@@:: Dashplayer :: MESSAGE FROM RENDERER ***************** kWhatRendererNotify:: %s",audio ? "audio" : "video"); - if (audio) { - mAudioEOS = true; - } else { - mVideoEOS = true; - } - - if (finalResult == ERROR_END_OF_STREAM) { - DP_MSG_ERROR("reached %s EOS", audio ? "audio" : "video"); - } else { - DP_MSG_ERROR("%s track encountered an error (%d)", - audio ? "audio" : "video", finalResult); - - notifyListener( - MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, finalResult); - } - - if ((mAudioEOS || mAudioDecoder == NULL) - && (mVideoEOS || mVideoDecoder == NULL)) { - if (finalResult == ERROR_END_OF_STREAM) { - notifyListener(MEDIA_PLAYBACK_COMPLETE, 0, 0); - } - } - } else if (what == Renderer::kWhatPosition) { - int64_t positionUs; - CHECK(msg->findInt64("positionUs", &positionUs)); - - CHECK(msg->findInt64("videoLateByUs", &mVideoLateByUs)); - DP_MSG_LOW("@@@@:: Dashplayer :: MESSAGE FROM RENDERER ***************** kWhatPosition:: position(%lld) VideoLateBy(%lld)",positionUs,mVideoLateByUs); - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit Notifyposition\n"); - break; - } - if (mDriver != NULL) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - driver->notifyPosition(positionUs); - mSource->notifyRenderingPosition(positionUs); - } - } - } else if (what == Renderer::kWhatFlushComplete) { - CHECK_EQ(what, (int32_t)Renderer::kWhatFlushComplete); - - int32_t audio; - CHECK(msg->findInt32("audio", &audio)); - DP_MSG_ERROR("@@@@:: Dashplayer :: MESSAGE FROM RENDERER ***************** kWhatFlushComplete:: %s",audio ? "audio" : "video"); - - } - break; - } - - case kWhatReset: - { - DP_MSG_ERROR("kWhatReset"); - Mutex::Autolock autoLock(mLock); - - if (mRenderer != NULL) { - // There's an edge case where the renderer owns all output - // buffers and is paused, therefore the decoder will not read - // more input data and will never encounter the matching - // discontinuity. To avoid this, we resume the renderer. - - if (mFlushingAudio == AWAITING_DISCONTINUITY - || mFlushingVideo == AWAITING_DISCONTINUITY) { - mRenderer->resume(); - } - } - if ( (mAudioDecoder != NULL && IsFlushingState(mFlushingAudio)) || - (mVideoDecoder != NULL && IsFlushingState(mFlushingVideo)) ) { - - // We're currently flushing, postpone the reset until that's - // completed. - - DP_MSG_MEDIUM("postponing reset mFlushingAudio=%d, mFlushingVideo=%d", - mFlushingAudio, mFlushingVideo); - - mResetPostponed = true; - break; - } - - if (mAudioDecoder == NULL && mVideoDecoder == NULL) { - finishReset(); - break; - } - - mTimeDiscontinuityPending = true; - - if (mAudioDecoder != NULL) { - flushDecoder(true /* audio */, true /* needShutdown */); - } - - if (mVideoDecoder != NULL) { - flushDecoder(false /* audio */, true /* needShutdown */); - } - - mResetInProgress = true; - break; - } - - case kWhatSeek: - { - if(mStats != NULL) { - mStats->notifySeek(); - } - - Mutex::Autolock autoLock(mLock); - int64_t seekTimeUs = -1, newSeekTime = -1; - status_t nRet = OK; - CHECK(msg->findInt64("seekTimeUs", &seekTimeUs)); - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit Seek\n"); - break; - } - - DP_MSG_ERROR("kWhatSeek seekTimeUs=%lld us (%.2f secs)", - seekTimeUs, (double)seekTimeUs / 1E6); - nRet = mSource->seekTo(seekTimeUs); - - if (nRet == OK) { // if seek success then flush the audio,video decoder and renderer - mTimeDiscontinuityPending = true; - bool audPresence = false; - bool vidPresence = false; - bool textPresence = false; - mSource->getMediaPresence(audPresence,vidPresence,textPresence); - mRenderer->setMediaPresence(true,audPresence); // audio - mRenderer->setMediaPresence(false,vidPresence); // video - if( (mVideoDecoder != NULL) && - (mFlushingVideo == NONE || mFlushingVideo == AWAITING_DISCONTINUITY) ) { - flushDecoder( false, true ); // flush video, shutdown - } - - if( (mAudioDecoder != NULL) && - (mFlushingAudio == NONE|| mFlushingAudio == AWAITING_DISCONTINUITY) ) - { - flushDecoder( true, true ); // flush audio, shutdown - } - if( mAudioDecoder == NULL ) { - DP_MSG_LOW("Audio is not there, set it to shutdown"); - mFlushingAudio = SHUT_DOWN; - } - if( mVideoDecoder == NULL ) { - DP_MSG_LOW("Video is not there, set it to shutdown"); - mFlushingVideo = SHUT_DOWN; - } - } - else if (nRet != PERMISSION_DENIED) { - mTimeDiscontinuityPending = true; - } - - // get the new seeked position - newSeekTime = seekTimeUs; - DP_MSG_LOW("newSeekTime %lld", newSeekTime); - mTimedTextCEASamplesDisc = true; - - if(mStats != NULL) { - mStats->logSeek(seekTimeUs); - } - - if (mDriver != NULL) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - if( newSeekTime >= 0 ) { - mRenderer->notifySeekPosition(newSeekTime); - driver->notifyPosition( newSeekTime ); - mSource->notifyRenderingPosition(newSeekTime); - driver->notifySeekComplete(); - } - } - } - - break; - } - - case kWhatPause: - { - DP_MSG_ERROR("kWhatPause"); - CHECK(mRenderer != NULL); - mRenderer->pause(); - - mPauseIndication = true; - - Mutex::Autolock autoLock(mLock); - if (mSource != NULL) - { - status_t nRet = mSource->pause(); - } - - break; - } - - case kWhatResume: - { - DP_MSG_ERROR("kWhatResume"); - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit Resume\n"); - break; - } - bool disc = mSource->isPlaybackDiscontinued(); - status_t status = OK; - - if (disc == true) - { - uint64_t nMin = 0, nMax = 0, nMaxDepth = 0; - status = mSource->getRepositionRange(&nMin, &nMax, &nMaxDepth); - if (status == OK) - { - int64_t seekTimeUs = (int64_t)nMin * 1000ll; - DP_MSG_ERROR("kWhatSeek seekTimeUs=%lld us (%.2f secs)", seekTimeUs, (double)seekTimeUs / 1E6); - status = mSource->seekTo(seekTimeUs); - if (status == OK) - { - // if seek success then flush the audio,video decoder and renderer - mTimeDiscontinuityPending = true; - bool audPresence = false; - bool vidPresence = false; - bool textPresence = false; - (void)mSource->getMediaPresence(audPresence,vidPresence,textPresence); - mRenderer->setMediaPresence(true,audPresence); // audio - mRenderer->setMediaPresence(false,vidPresence); // video - if( (mVideoDecoder != NULL) && - (mFlushingVideo == NONE || mFlushingVideo == AWAITING_DISCONTINUITY) ) { - flushDecoder( false, true ); // flush video, shutdown - } - - if( (mAudioDecoder != NULL) && - (mFlushingAudio == NONE|| mFlushingAudio == AWAITING_DISCONTINUITY) ) - { - flushDecoder( true, true ); // flush audio, shutdown - } - if( mAudioDecoder == NULL ) { - DP_MSG_MEDIUM("Audio is not there, set it to shutdown"); - mFlushingAudio = SHUT_DOWN; - } - if( mVideoDecoder == NULL ) { - DP_MSG_MEDIUM("Video is not there, set it to shutdown"); - mFlushingVideo = SHUT_DOWN; - } - - if (mDriver != NULL) - { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) - { - if( seekTimeUs >= 0 ) { - mRenderer->notifySeekPosition(seekTimeUs); - driver->notifyPosition( seekTimeUs ); - } - } - } - - mTimedTextCEASamplesDisc = true; - } - } - } - - if (status != OK && status != ERROR_END_OF_STREAM) - { - //Notify error? - DP_MSG_ERROR(" Dash Source playback discontinuity check failure"); - notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, status); - } - - Mutex::Autolock autoLock(mLock); - if (mSource != NULL) { - status_t nRet = mSource->resume(); - } - - if (mAudioDecoder == NULL || mVideoDecoder == NULL || mTextDecoder == NULL) { - mScanSourcesPending = false; - postScanSources(); - } - - CHECK(mRenderer != NULL); - mRenderer->resume(); - - mPauseIndication = false; - - break; - } - - case kWhatPrepareAsync: - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null in prepareAsync\n"); - break; - } - - DP_MSG_ERROR("kWhatPrepareAsync"); - mSource->prepareAsync(); - postIsPrepareDone(); - break; - - case kWhatIsPrepareDone: - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null when checking for prepare done\n"); - break; - } - - status_t err; - err = mSource->isPrepareDone(); - if(err == OK) { - int64_t durationUs; - if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - driver->notifyDuration(durationUs); - } - } - DP_MSG_ERROR("PrepareDone complete\n"); - notifyListener(MEDIA_PREPARED, 0, 0); - } else if(err == -EWOULDBLOCK) { - msg->post(100000ll); - } else { - DP_MSG_ERROR("Prepareasync failed\n"); - notifyListener(MEDIA_ERROR, MEDIA_ERROR_UNKNOWN, err); - } - break; - case kWhatSourceNotify: - { - Mutex::Autolock autoLock(mLock); - DP_MSG_ERROR("kWhatSourceNotify"); - - if(mSource != NULL) { - int64_t track; - - sp<AMessage> sourceRequest; - DP_MSG_MEDIUM("kWhatSourceNotify - looking for source-request"); - - // attempt to find message by different names - bool msgFound = msg->findMessage("source-request", &sourceRequest); - int32_t handled; - if (!msgFound){ - DP_MSG_MEDIUM("kWhatSourceNotify source-request not found, trying using sourceRequestID"); - char srName[] = "source-request00"; - (void)snprintf(srName, sizeof(srName), "source-request%d%d", mSRid/10, mSRid%10); - msgFound = msg->findMessage(srName, &sourceRequest); - if(msgFound) - mSRid = (mSRid+1)%SRMax; - } - - if(msgFound) - { - int32_t what; - CHECK(sourceRequest->findInt32("what", &what)); - - if (what == kWhatBufferingStart) { - sourceRequest->findInt64("track", &track); - getTrackName((int)track,mTrackName); - DP_MSG_ERROR("Source Notified Buffering Start for %s ",mTrackName); - if (mBufferingNotification == false) { - if (track == kVideo && mNativeWindow == NULL) - { - DP_MSG_ERROR("video decoder not instantiated, no buffering for video(%d)", - mBufferingNotification); - } - else - { - mBufferingNotification = true; - notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_START, 0); - } - } - else { - DP_MSG_MEDIUM("Buffering Start Event Already Notified mBufferingNotification(%d)", - mBufferingNotification); - } - } - else if(what == kWhatBufferingEnd) { - sourceRequest->findInt64("track", &track); - getTrackName((int)track,mTrackName); - if (mBufferingNotification) { - DP_MSG_ERROR("Source Notified Buffering End for %s ",mTrackName); - mBufferingNotification = false; - notifyListener(MEDIA_INFO, MEDIA_INFO_BUFFERING_END, 0); - if(mStats != NULL) { - mStats->notifyBufferingEvent(); - } - } - else { - DP_MSG_MEDIUM("No need to notify Buffering end as mBufferingNotification is (%d) " - ,mBufferingNotification); - } - } - } - } - else { - DP_MSG_ERROR("kWhatSourceNotify - Source object does not exist anymore"); - } - break; - } - case kWhatQOE: - { - sp<AMessage> dataQOE; - Parcel notifyDataQOE; - int64_t timeofday; - bool msgFound = msg->findMessage("QOEData", &dataQOE); - if (msgFound) - { - int32_t what; - CHECK(dataQOE->findInt32("what", &what)); - if (what == kWhatQOEPlay) - { - dataQOE->findInt64("timeofday",&timeofday); - - notifyDataQOE.writeInt64(timeofday); - } - else if (what == kWhatQOEStop) - { - int32_t bandwidth = 0; - int32_t reBufCount = 0; - int32_t stopSize = 0; - int32_t videoSize = 0; - AString stopPhrase; - AString videoUrl; - - dataQOE->findInt64("timeofday",&timeofday); - dataQOE->findInt32("bandwidth",&bandwidth); - dataQOE->findInt32("rebufct",&reBufCount); - dataQOE->findInt32("sizestopphrase",&stopSize); - dataQOE->findString("stopphrase",&stopPhrase); - dataQOE->findInt32("sizevideo",&videoSize); - dataQOE->findString("videourl",&videoUrl); - - notifyDataQOE.writeInt32(bandwidth); - notifyDataQOE.writeInt32(reBufCount); - notifyDataQOE.writeInt64(timeofday); - notifyDataQOE.writeInt32(stopSize); - notifyDataQOE.writeInt32(stopSize); - stopPhrase.append('\0'); - notifyDataQOE.write((const uint8_t *)stopPhrase.c_str(), stopSize+1); - notifyDataQOE.writeInt32(videoSize); - notifyDataQOE.writeInt32(videoSize); - videoUrl.append('\0'); - notifyDataQOE.write((const uint8_t *)videoUrl.c_str(), videoSize+1); - - } - else if (what == kWhatQOESwitch) - { - int32_t bandwidth = 0; - int32_t reBufCount = 0; - - dataQOE->findInt64("timeofday",&timeofday); - dataQOE->findInt32("bandwidth",&bandwidth); - dataQOE->findInt32("rebufct",&reBufCount); - - notifyDataQOE.writeInt32(bandwidth); - notifyDataQOE.writeInt32(reBufCount); - notifyDataQOE.writeInt64(timeofday); - } - notifyListener(MEDIA_QOE,kWhatQOE,what,¬ifyDataQOE); - } - break; - } - - default: - TRESPASS(); - break; - } -} - -void DashPlayer::finishFlushIfPossible() { - - /* check if Audio Decoder has been shutdown for handling audio discontinuity - ,in that case Audio decoder has to be reinstaniated*/ - if (mAudioDecoder == NULL && (mFlushingAudio == SHUT_DOWN) && - !mResetInProgress && !mResetPostponed && - ((mVideoDecoder != NULL) && (mFlushingVideo == NONE || mFlushingVideo == AWAITING_DISCONTINUITY))) - { - DP_MSG_LOW("Resuming Audio after Shutdown(Discontinuity)"); - mFlushingAudio = NONE; - postScanSources(); - return; - } - //If reset was postponed after one of the streams is flushed, complete it now - if (mResetPostponed) { - DP_MSG_LOW("finishFlushIfPossible Handle reset postpone "); - if ((mAudioDecoder != NULL) && - (mFlushingAudio == NONE || mFlushingAudio == AWAITING_DISCONTINUITY )) { - flushDecoder( true, true ); - } - if ((mVideoDecoder != NULL) && - (mFlushingVideo == NONE || mFlushingVideo == AWAITING_DISCONTINUITY )) { - flushDecoder( false, true ); - } - } - - //Check if both audio & video are flushed - if (mFlushingAudio != FLUSHED && mFlushingAudio != SHUT_DOWN) { - DP_MSG_LOW("Dont finish flush, audio is in state %d ", mFlushingAudio); - return; - } - - if (mFlushingVideo != FLUSHED && mFlushingVideo != SHUT_DOWN) { - DP_MSG_LOW("Dont finish flush, video is in state %d ", mFlushingVideo); - return; - } - - DP_MSG_HIGH("both audio and video are flushed now."); - - if ((mRenderer != NULL) && (mTimeDiscontinuityPending) && - !isSetSurfaceTexturePending) { - mRenderer->signalTimeDiscontinuity(); - mTimeDiscontinuityPending = false; - } - - if (mAudioDecoder != NULL) { - DP_MSG_LOW("Resume Audio after flush"); - mAudioDecoder->signalResume(); - } - - if (mVideoDecoder != NULL) { - DP_MSG_LOW("Resume Video after flush"); - mVideoDecoder->signalResume(); - } - - mFlushingAudio = NONE; - mFlushingVideo = NONE; - - if (mResetInProgress) { - DP_MSG_ERROR("reset completed"); - - mResetInProgress = false; - finishReset(); - } else if (mResetPostponed) { - (new AMessage(kWhatReset, this))->post(); - mResetPostponed = false; - DP_MSG_LOW("Handle reset postpone"); - }else if(isSetSurfaceTexturePending){ - processDeferredActions(); - DP_MSG_ERROR("DashPlayer::finishFlushIfPossible() setsurfacetexturepending=true"); - } else if (mAudioDecoder == NULL || mVideoDecoder == NULL) { - DP_MSG_LOW("Start scanning for sources after shutdown"); - if (mTextDecoder != NULL) - { - if (mSource != NULL) { - DP_MSG_LOW("finishFlushIfPossible calling mSource->stop"); - mSource->stop(); - } - sp<AMessage> codecRequest; - mTextNotify->findMessage("codec-request", &codecRequest); - codecRequest = NULL; - mTextNotify = NULL; - looper()->unregisterHandler(mTextDecoder->id()); - mTextDecoder.clear(); - } - postScanSources(); - } -} - -void DashPlayer::finishReset() { - CHECK(mAudioDecoder == NULL); - CHECK(mVideoDecoder == NULL); - - ++mScanSourcesGeneration; - mScanSourcesPending = false; - - if (mRenderer != NULL) { - looper()->unregisterHandler(mRenderer->id()); - mRenderer.clear(); - } - - if (mSource != NULL) { - DP_MSG_ERROR("finishReset calling mSource->stop"); - mSource->stop(); - mSource.clear(); - } - - if ( (mTextDecoder != NULL) && (mTextNotify != NULL)) - { - sp<AMessage> codecRequest; - mTextNotify->findMessage("codec-request", &codecRequest); - codecRequest = NULL; - mTextNotify = NULL; - looper()->unregisterHandler(mTextDecoder->id()); - mTextDecoder.clear(); - DP_MSG_ERROR("Text Dummy Decoder Deleted"); - } - if (mSourceNotify != NULL) - { - sp<AMessage> sourceRequest; - mSourceNotify->findMessage("source-request", &sourceRequest); - sourceRequest = NULL; - for (int id = 0; id < SRMax; id++){ - char srName[] = "source-request00"; - (void)snprintf(srName, sizeof(srName), "source-request%d%d", id/10, id%10); - mSourceNotify->findMessage(srName, &sourceRequest); - sourceRequest = NULL; - } - mSourceNotify = NULL; - } - - if (mDriver != NULL) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - driver->notifyResetComplete(); - } - } -} - -void DashPlayer::postScanSources() { - if (mScanSourcesPending) { - return; - } - - sp<AMessage> msg = new AMessage(kWhatScanSources, this); - msg->setInt32("generation", mScanSourcesGeneration); - msg->post(); - - mScanSourcesPending = true; -} - -status_t DashPlayer::instantiateDecoder(int track, sp<Decoder> *decoder) { - DP_MSG_LOW("@@@@:: instantiateDecoder Called "); - if (*decoder != NULL) { - return OK; - } - if (mSource == NULL) - { - DP_MSG_ERROR("Source is null. Exit instantiateDecoder\n"); - return -EWOULDBLOCK; - } - - sp<MetaData> meta = mSource->getFormat(track); - - if (meta == NULL) { - return -EWOULDBLOCK; - } - - if (track == kVideo) { - const char *mime = NULL; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - mVideoIsAVC = !strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime); - if(mStats != NULL) { - mStats->setMime(mime); - } - - if (mSetVideoSize) { - int32_t width = 0; - meta->findInt32(kKeyWidth, &width); - int32_t height = 0; - meta->findInt32(kKeyHeight, &height); - DP_MSG_HIGH("instantiate video decoder, send wxh = %dx%d",width,height); - notifyListener(MEDIA_SET_VIDEO_SIZE, width, height); - mSetVideoSize = false; - } - } - - sp<AMessage> notify; - if (track == kAudio) { - notify = new AMessage(kWhatAudioNotify ,this); - DP_MSG_HIGH("Creating Audio Decoder "); - *decoder = new Decoder(notify); - DP_MSG_LOW("@@@@:: setting Sink/Renderer pointer to decoder"); - if (mRenderer != NULL) { - mRenderer->setMediaPresence(true,true); - } - } else if (track == kVideo) { - notify = new AMessage(kWhatVideoNotify ,this); - *decoder = new Decoder(notify, mNativeWindow); - DP_MSG_HIGH("Creating Video Decoder "); - if (mRenderer != NULL) { - mRenderer->setMediaPresence(false,true); - } - } else if (track == kText) { - mTextNotify = new AMessage(kWhatTextNotify ,this); - *decoder = new Decoder(mTextNotify); - sp<AMessage> codecRequest = new AMessage; - codecRequest->setInt32("what", Decoder::kWhatFillThisBuffer); - mTextNotify->setMessage("codec-request", codecRequest); - DP_MSG_HIGH("Creating Dummy Text Decoder "); - if (mSource != NULL) { - mSource->setupSourceData(mTextNotify, track); - } - } - - if(track != kAudio && track != kVideo) - { - looper()->registerHandler(*decoder); - } - - char value[PROPERTY_VALUE_MAX] = {0}; - //Set flushing state to none - Mutex::Autolock autoLock(mLock); - if(track == kAudio) { - mFlushingAudio = NONE; - } else if (track == kVideo) { - mFlushingVideo = NONE; - } - - if( (track == kAudio || track == kVideo) && ((*decoder) != NULL)) { - (*decoder)->init(); - (*decoder)->configure(meta); - } - - int64_t durationUs; - if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - driver->notifyDuration(durationUs); - } - } - - return OK; -} - -status_t DashPlayer::feedDecoderInputData(int track, const sp<AMessage> &msg) { - sp<AMessage> reply; - - if ( (track != kText) && !(msg->findMessage("reply", &reply))) - { - CHECK(msg->findMessage("reply", &reply)); - } - - { - Mutex::Autolock autoLock(mLock); - - if (reply != NULL && (((track == kAudio) && IsFlushingState(mFlushingAudio)) - || ((track == kVideo) && IsFlushingState(mFlushingVideo)) - || mSource == NULL)) { - reply->setInt32("err", INFO_DISCONTINUITY); - reply->post(); - return OK; - } - } - - getTrackName(track,mTrackName); - - sp<ABuffer> accessUnit; - - bool dropAccessUnit; - do { - - status_t err = (status_t)UNKNOWN_ERROR; - - err = mSource->dequeueAccessUnit(track, &accessUnit); - - if (err == -EWOULDBLOCK) { - return err; - } else if (err != OK) { - if (err == INFO_DISCONTINUITY) { - int32_t type; - CHECK(accessUnit->meta()->findInt32("discontinuity", &type)); - - bool formatChange = - ((track == kAudio) && - (type & ATSParser::DISCONTINUITY_AUDIO_FORMAT)) - || ((track == kVideo) && - (type & ATSParser::DISCONTINUITY_VIDEO_FORMAT)); - - bool timeChange = (type & ATSParser::DISCONTINUITY_TIME) != 0; - - DP_MSG_HIGH("%s discontinuity (formatChange=%d, time=%d)", - mTrackName, formatChange, timeChange); - - if (track == kAudio) { - mSkipRenderingAudioUntilMediaTimeUs = -1; - } else if (track == kVideo) { - mSkipRenderingVideoUntilMediaTimeUs = -1; - } - - if (timeChange) { - sp<AMessage> extra; - if (accessUnit->meta()->findMessage("extra", &extra) - && extra != NULL) { - int64_t resumeAtMediaTimeUs; - if (extra->findInt64( - "resume-at-mediatimeUs", &resumeAtMediaTimeUs)) { - DP_MSG_HIGH("suppressing rendering of %s until %lld us", - mTrackName, resumeAtMediaTimeUs); - - if (track == kAudio) { - mSkipRenderingAudioUntilMediaTimeUs = - resumeAtMediaTimeUs; - } else if (track == kVideo) { - mSkipRenderingVideoUntilMediaTimeUs = - resumeAtMediaTimeUs; - } - } - } - } - - mTimeDiscontinuityPending = - mTimeDiscontinuityPending || timeChange; - - if (formatChange || timeChange) { - flushDecoder(track, formatChange); - } else { - // This stream is unaffected by the discontinuity - - if (track == kAudio) { - mFlushingAudio = FLUSHED; - } else if (track == kVideo) { - mFlushingVideo = FLUSHED; - } - - finishFlushIfPossible(); - - return -EWOULDBLOCK; - } - } - - if ( (track == kAudio) || - (track == kVideo)) - { - reply->setInt32("err", err); - reply->post(); - return OK; - } - else if ((track == kText) && - (err == ERROR_END_OF_STREAM || err == (status_t)UNKNOWN_ERROR)) { - DP_MSG_ERROR("Text track has encountered error %d", err ); - sendTextPacket(NULL, err); - return err; - } - } - - dropAccessUnit = false; - if (track == kVideo) { - - if(mStats != NULL) { - mStats->incrementTotalFrames(); - } - - if (mVideoLateByUs > 100000ll - && mVideoIsAVC - && !IsAVCReferenceFrame(accessUnit)) { - dropAccessUnit = true; - if(mStats != NULL) { - mStats->incrementDroppedFrames(); - } - } - } - } while (dropAccessUnit); - - // DP_MSG_LOW("returned a valid buffer of %s data", mTrackName); - - if (track == kVideo || track == kAudio) { - reply->setBuffer("buffer", accessUnit); - reply->post(); - } else if (track == kText) { - sendTextPacket(accessUnit,OK); - if (mSource != NULL) { - mSource->postNextTextSample(accessUnit,mTextNotify,track); - } - } - return OK; -} - -void DashPlayer::renderBuffer(bool audio, const sp<AMessage> &msg) { - // DP_MSG_LOW("renderBuffer %s", audio ? "audio" : "video"); - - sp<AMessage> reply; - CHECK(msg->findMessage("reply", &reply)); - - Mutex::Autolock autoLock(mLock); - if (IsFlushingState(audio ? mFlushingAudio : mFlushingVideo)) { - // We're currently attempting to flush the decoder, in order - // to complete this, the decoder wants all its buffers back, - // so we don't want any output buffers it sent us (from before - // we initiated the flush) to be stuck in the renderer's queue. - - DP_MSG_MEDIUM("we're still flushing the %s decoder, sending its output buffer" - " right back.", audio ? "audio" : "video"); - - reply->post(); - return; - } - - sp<ABuffer> buffer; - CHECK(msg->findBuffer("buffer", &buffer)); - - int64_t &skipUntilMediaTimeUs = - audio - ? mSkipRenderingAudioUntilMediaTimeUs - : mSkipRenderingVideoUntilMediaTimeUs; - - if (skipUntilMediaTimeUs >= 0) { - int64_t mediaTimeUs; - CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); - - if (mediaTimeUs < skipUntilMediaTimeUs) { - DP_MSG_HIGH("dropping %s buffer at time %lld as requested.", - audio ? "audio" : "video", - mediaTimeUs); - - reply->post(); - return; - } - - skipUntilMediaTimeUs = -1; - } - - if(mRenderer != NULL) - { - if(!audio) - { - int32_t extradata = 0; - - if (buffer->meta()->findInt32("extradata", &extradata) && 1 == extradata) - { - DP_MSG_HIGH("kwhatdrainthisbuffer: Decoded sample contains SEI. Parse for CEA encoded cc extradata"); - - sp<RefBase> obj; - - if (buffer->meta()->findObject("graphic-buffer", &obj)) - { - sp<GraphicBuffer> graphicBuffer = static_cast<GraphicBuffer*>(obj.get()); - if (graphicBuffer != NULL) - { - DP_MSG_LOW("kwhatdrainthisbuffer: Extradata present", - "graphicBuffer = %p, width=%d height=%d color-format=%d", - graphicBuffer.get(), mCurrentWidth, mCurrentHeight, mColorFormat); - - if (mColorFormat == 0x7FA30C04 /*OMX_QCOM_COLOR_FormatYUV420PackedSemiPlanar32m*/) - { - size_t filledLen = (VENUS_Y_STRIDE(COLOR_FMT_NV12, mCurrentWidth) - * VENUS_Y_SCANLINES(COLOR_FMT_NV12, mCurrentHeight)) - + (VENUS_UV_STRIDE(COLOR_FMT_NV12, mCurrentWidth) - * VENUS_UV_SCANLINES(COLOR_FMT_NV12, mCurrentHeight)); - size_t allocLen = VENUS_BUFFER_SIZE(COLOR_FMT_NV12, mCurrentWidth, mCurrentHeight); - size_t offset = buffer->offset(); - - DP_MSG_LOW("kwhatdrainthisbuffer: decoded buffer ranges " - "filledLen = %lu, allocLen = %lu, startOffset = %lu", - filledLen, allocLen, offset); - - // 'lock' returns mapped virtual address that can be read from or written into - // Use GRALLOC_USAGE_SW_READ_MASK / WRITE_MASK to indicate access type - // 'unlock' will unmap the mapped address - - void *yuvData = NULL; - graphicBuffer->lock(GRALLOC_USAGE_SW_READ_MASK, &yuvData); - - if (yuvData) - { - OMX_OTHER_EXTRADATATYPE *pExtra; - pExtra = (OMX_OTHER_EXTRADATATYPE *)((unsigned long)((OMX_U8*)yuvData + offset + filledLen + 3)&(~3)); - - while (pExtra && - ((OMX_U8*)pExtra + pExtra->nSize) <= ((OMX_U8*)yuvData + allocLen) && - pExtra->eType != OMX_ExtraDataNone ) - { - DP_MSG_LOW( - "============== Extra Data ==============\n" - " Size: %lu\n" - " Version: %lu\n" - " PortIndex: %lu\n" - " Type: %x\n" - " DataSize: %lu", - pExtra->nSize, pExtra->nVersion.nVersion, - pExtra->nPortIndex, pExtra->eType, pExtra->nDataSize); - - if(pExtra->eType == (OMX_EXTRADATATYPE) OMX_ExtraDataMP2UserData) - { - OMX_QCOM_EXTRADATA_USERDATA *userdata = (OMX_QCOM_EXTRADATA_USERDATA *)pExtra->data; - OMX_U8 *data_ptr = (OMX_U8 *)userdata->data; - OMX_U32 userdata_size = pExtra->nDataSize - sizeof(userdata->type); - - DP_MSG_LOW( - "-------------- OMX_ExtraDataMP2UserData Userdata -------------\n" - " Stream userdata type: %lu\n" - " userdata size: %lu\n" - " STREAM_USERDATA:", - userdata->type, userdata_size); - - for (uint32_t i = 0; i < userdata_size; i+=4) { - DP_MSG_LOW(" %x %x %x %x", - data_ptr[i], data_ptr[i+1], - data_ptr[i+2], data_ptr[i+3]); - } - - DP_MSG_LOW( - "-------------- End of OMX_ExtraDataMP2UserData Userdata -----------"); - - /* - SEI Syntax - - user_data_registered_itu_t_t35 ( ) { - itu_t_t35_country_code (8 bits) - itu_t_t35_provider_code (16 bits) - user_identifier (32 bits) - user_structure( ) - } - - cc_data parsing logic - 1. itu_t_t35_country_code - A fixed 8-bit field, the value of which shall be 0xB5.3 - itu_t_35_provider_code - A fixed 16-bit field, the value of which shall be 0x0031. - 2. user_identifier should match 0x47413934 ('GA94') ATSC_user_data( ) - - ATSC_user_data Syntax - ATSC_user_data() { - user_data_type_code (8 bits) - user_data_type_structure() - } - - 3. user_data_type_code should match 0x03 MPEG_cc_data() - - */ - - if(0xB5 == data_ptr[0] && 0x00 == data_ptr[1] && 0x31 == data_ptr[2] - && 0x47 == data_ptr[3] && 0x41 == data_ptr[4] && 0x39 == data_ptr[5] && 0x34 == data_ptr[6] - && 0x03 == data_ptr[7]) - { - DP_MSG_HIGH("SEI payload user_data_type_code is CEA encoded MPEG_cc_data()"); - - OMX_U32 cc_data_size = 0; - for(int i = 8; data_ptr[i] != 0xFF /*each cc_data ends with marker bits*/; i++) - { - cc_data_size++; - } - - if(cc_data_size > 0) - { - DP_MSG_LOW( - "-------------- MPEG_cc_data() -------------\n" - " cc_data ptr: %p cc_data_size: %lu\n", - &data_ptr[8], cc_data_size); - - for (uint32_t i = 8; i < 8 + cc_data_size; i+=4) { - DP_MSG_LOW(" %x %x %x %x", - data_ptr[i], data_ptr[i+1], - data_ptr[i+2], data_ptr[i+3]); - } - - DP_MSG_LOW( - "-------------- End of MPEG_cc_data() -------------\n"); - - sp<ABuffer> accessUnit = new ABuffer((OMX_U8*)&data_ptr[8], cc_data_size); - - int64_t mediaTimeUs; - - sp<ABuffer> buffer; - CHECK(msg->findBuffer("buffer", &buffer)); - CHECK(buffer->meta()->findInt64("timeUs", &mediaTimeUs)); - accessUnit->meta()->setInt64("timeUs",mediaTimeUs); - - //To signal discontinuity in samples during seek and resume-out-of-tsb(internal seek) operations - if(mTimedTextCEASamplesDisc) - { - accessUnit->meta()->setInt32("disc", 1); - mTimedTextCEASamplesDisc = false; - } - - //Indicate timedtext CEA present in stream. Used to signal EOS in Codec::kWhatEOS - if(!mTimedTextCEAPresent) - { - mTimedTextCEAPresent = true; - } - - sendTextPacket(accessUnit, OK, TIMED_TEXT_CEA); - - accessUnit = NULL; - break; - } - } - } - - pExtra = (OMX_OTHER_EXTRADATATYPE *) (((OMX_U8 *) pExtra) + pExtra->nSize); - } - graphicBuffer->unlock(); - } - } - } - } - } - } - - mRenderer->queueBuffer(audio, buffer, reply); - } -} - -void DashPlayer::notifyListener(int msg, int ext1, int ext2, const Parcel *obj) { - if (mDriver == NULL) { - return; - } - - sp<DashPlayerDriver> driver = mDriver.promote(); - - if (driver == NULL) { - return; - } - - driver->notifyListener(msg, ext1, ext2, obj); -} - -void DashPlayer::flushDecoder(bool audio, bool needShutdown) { - if ((audio && mAudioDecoder == NULL) || (!audio && mVideoDecoder == NULL)) { - DP_MSG_HIGH("flushDecoder %s without decoder present", - audio ? "audio" : "video"); - } - - // Make sure we don't continue to scan sources until we finish flushing. - ++mScanSourcesGeneration; - mScanSourcesPending = false; - - (audio ? mAudioDecoder : mVideoDecoder)->signalFlush(); - - if(mRenderer != NULL) { - mRenderer->flush(audio); - } - - FlushStatus newStatus = - needShutdown ? FLUSHING_DECODER_SHUTDOWN : FLUSHING_DECODER; - - if (audio) { - CHECK(mFlushingAudio == NONE - || mFlushingAudio == AWAITING_DISCONTINUITY); - - mFlushingAudio = newStatus; - - if (mFlushingVideo == NONE) { - mFlushingVideo = (mVideoDecoder != NULL) - ? AWAITING_DISCONTINUITY - : FLUSHED; - } - } else { - CHECK(mFlushingVideo == NONE - || mFlushingVideo == AWAITING_DISCONTINUITY); - - mFlushingVideo = newStatus; - - if (mFlushingAudio == NONE) { - mFlushingAudio = (mAudioDecoder != NULL) - ? AWAITING_DISCONTINUITY - : FLUSHED; - } - } -} - -sp<DashPlayer::Source> - DashPlayer::LoadCreateSource(const char * uri, const KeyedVector<String8,String8> *headers, - bool uidValid, uid_t uid) -{ - const char* STREAMING_SOURCE_LIB = "libmmipstreamaal.so"; - const char* DASH_HTTP_LIVE_CREATE_SOURCE = "CreateDashHttpLiveSource"; - void* pStreamingSourceLib = NULL; - - typedef DashPlayer::Source* (*SourceFactory)(const char * uri, const KeyedVector<String8, String8> *headers, bool uidValid, uid_t uid); - - /* Open librery */ - pStreamingSourceLib = ::dlopen(STREAMING_SOURCE_LIB, RTLD_LAZY); - - if (pStreamingSourceLib == NULL) { - DP_MSG_ERROR("@@@@:: STREAMING Source Library (libmmipstreamaal.so) Load Failed Error : %s ",::dlerror()); - return NULL; - } - - SourceFactory StreamingSourcePtr = NULL; - - StreamingSourcePtr = (SourceFactory) dlsym(pStreamingSourceLib, DASH_HTTP_LIVE_CREATE_SOURCE); - - if (StreamingSourcePtr == NULL) { - DP_MSG_ERROR("@@@@:: CreateDashHttpLiveSource symbol not found in libmmipstreamaal.so, return NULL "); - return NULL; - } - - /*Get the Streaming (DASH) Source object, which will be used to communicate with Source (DASH) */ - sp<DashPlayer::Source> StreamingSource = StreamingSourcePtr(uri, headers, uidValid, uid); - - if(StreamingSource==NULL) { - DP_MSG_ERROR("@@@@:: StreamingSource failed to instantiate Source "); - return NULL; - } - - return StreamingSource; -} - -status_t DashPlayer::prepareAsync() // only for DASH -{ - sp<AMessage> msg = new AMessage(kWhatPrepareAsync, this); - if (msg == NULL) - { - DP_MSG_ERROR("Out of memory, AMessage is null for kWhatPrepareAsync\n"); - return NO_MEMORY; - } - msg->post(); - return -EWOULDBLOCK; - - return OK; -} - -status_t DashPlayer::getParameter(int key, Parcel *reply) -{ - void * data_8; - void * data_16; - size_t data_8_Size; - size_t data_16_Size; - - status_t err = OK; - - if (mSource == NULL) - { - DP_MSG_ERROR("Source is NULL in getParameter\n"); - return ((status_t)UNKNOWN_ERROR); - } - if (key == KEY_DASH_REPOSITION_RANGE) - { - uint64_t nMin = 0, nMax = 0, nMaxDepth = 0; - err = mSource->getRepositionRange(&nMin, &nMax, &nMaxDepth); - if(err == OK || err == ERROR_END_OF_STREAM) - { - reply->setDataPosition(0); - reply->writeInt64(nMin); - reply->writeInt64(nMax); - reply->writeInt64(nMaxDepth); - err = OK; - DP_MSG_LOW("DashPlayer::getParameter KEY_DASH_REPOSITION_RANGE %lld, %lld", nMin, nMax); - } - else - { - DP_MSG_ERROR("DashPlayer::getParameter KEY_DASH_REPOSITION_RANGE err in NOT OK"); - } - } - else if(key == INVOKE_ID_GET_TRACK_INFO) - { - size_t numInbandTracks = (mSource != NULL) ? mSource->getTrackCount() : 0; - DP_MSG_HIGH("DashPlayer::getParameter #InbandTracks %d ", numInbandTracks); - // total track count - reply->writeInt32(numInbandTracks); - // write inband tracks - for (size_t i = 0; i < numInbandTracks; ++i) { - writeTrackInfo(reply, mSource->getTrackInfo(i)); - } - } - else - { - err = mSource->getParameter(key, &data_8, &data_8_Size); - if (key == KEY_DASH_QOE_PERIODIC_EVENT) - { - if (err == OK) - { - if(data_8) - { - sp<AMessage> dataQOE; - dataQOE = (AMessage*)(data_8); - int32_t bandwidth = 0; - int32_t ipaddSize = 0; - int32_t videoSize = 0; - int64_t timeofday = 0; - AString ipAdd; - AString videoUrl; - - dataQOE->findInt64("timeofday",&timeofday); - dataQOE->findInt32("bandwidth",&bandwidth); - dataQOE->findInt32("sizeipadd",&ipaddSize); - dataQOE->findString("ipaddress",&ipAdd); - dataQOE->findInt32("sizevideo",&videoSize); - dataQOE->findString("videourl",&videoUrl); - - reply->setDataPosition(0); - reply->writeInt32(bandwidth); - reply->writeInt64(timeofday); - reply->writeInt32(ipaddSize); - reply->writeInt32(ipaddSize); - reply->write((const uint8_t *)ipAdd.c_str(), ipaddSize); - reply->writeInt32(videoSize); - reply->writeInt32(videoSize); - videoUrl.append('\0'); - reply->write((const uint8_t *)videoUrl.c_str(), videoSize+1); - }else - { - DP_MSG_ERROR("DashPlayerStats::getParameter : data_8 is null"); - } - } - } - else - { - if (err != OK) - { - DP_MSG_ERROR("source getParameter returned error: %d\n",err); - return err; - } - - data_16_Size = data_8_Size * sizeof(char16_t); - data_16 = malloc(data_16_Size); - if (data_16 == NULL) - { - DP_MSG_ERROR("Out of memory in getParameter\n"); - return NO_MEMORY; - } - - utf8_to_utf16_no_null_terminator((uint8_t *)data_8, data_8_Size, (char16_t *) data_16); - err = reply->writeString16((char16_t *)data_16, data_8_Size); - free(data_16); - } - } - return err; -} - -void DashPlayer::writeTrackInfo( - Parcel* reply, const sp<AMessage> format) const -{ - int32_t trackType; - AString lang; - AString mime; - CHECK(format->findInt32("type", &trackType)); - CHECK(format->findString("language", &lang)); - CHECK(format->findString("mime", &mime)); - reply->writeInt32(2); - reply->writeInt32(trackType); - reply->writeString16(String16(mime.c_str())); - reply->writeString16(String16(lang.c_str())); -} - - - -status_t DashPlayer::setParameter(int key, const Parcel &request) -{ - status_t err = (status_t)UNKNOWN_ERROR;; - if (KEY_DASH_ADAPTION_PROPERTIES == key || - KEY_DASH_SET_ADAPTION_PROPERTIES == key) - { - size_t len = 0; - const char16_t* str = request.readString16Inplace(&len); - void * data = malloc(len + 1); - if (data == NULL) - { - DP_MSG_ERROR("Out of memory in setParameter\n"); - return NO_MEMORY; - } - - utf16_to_utf8(str, len, (char*) data); - if (mSource != NULL) - { - err = mSource->setParameter(key, data, len); - } - free(data); - }else if(key == KEY_DASH_QOE_EVENT) - { - int value = request.readInt32(); - if (mSource != NULL) - { - err = mSource->setParameter(key, &value, sizeof(value)); - } - } - return err; -} - -void DashPlayer::postIsPrepareDone() -{ - sp<AMessage> msg = new AMessage(kWhatIsPrepareDone, this); - if (msg == NULL) - { - DP_MSG_ERROR("Out of memory, AMessage is null for kWhatIsPrepareDone\n"); - return; - } - msg->post(); -} -void DashPlayer::sendTextPacket(sp<ABuffer> accessUnit,status_t err, TimedTextType eTimedTextType) -{ - if(!mQCTimedTextListenerPresent) - { - return; - } - - Parcel parcel; - int mFrameType = TIMED_TEXT_FLAG_FRAME; - - //Local setting - parcel.writeInt32(KEY_LOCAL_SETTING); - - parcel.writeInt32(KEY_TEXT_FORMAT); - // UPDATE TIMEDTEXT SAMPLE TYPE - //Currently dash only support SMPTE-TT and CEA formats. No support for other timedtext types (like WebVTT, SRT) - if(eTimedTextType == TIMED_TEXT_SMPTE) - { - parcel.writeString16((String16)"smptett"); - } - else if(eTimedTextType == TIMED_TEXT_CEA) - { - parcel.writeString16((String16)"cea"); - } - else - { - parcel.writeString16((String16)"unknown"); - } - - // UPDATE TIMEDTEXT SAMPLE FLAGS - parcel.writeInt32(KEY_TEXT_FLAG_TYPE); - if (err == ERROR_END_OF_STREAM || - err == (status_t)UNKNOWN_ERROR) - { - parcel.writeInt32(TIMED_TEXT_FLAG_EOS); - // write size of sample - DP_MSG_ERROR("sendTextPacket Error End Of Stream EOS"); - mFrameType = TIMED_TEXT_FLAG_EOS; - notifyListener(MEDIA_TIMED_TEXT, 0, mFrameType, &parcel); - return; - } - - int32_t tCodecConfig = 0; - accessUnit->meta()->findInt32("conf", &tCodecConfig); - if(tCodecConfig) - { - DP_MSG_HIGH("Timed text codec config frame"); - parcel.writeInt32(TIMED_TEXT_FLAG_CODEC_CONFIG); - mFrameType = TIMED_TEXT_FLAG_CODEC_CONFIG; - } - else - { - parcel.writeInt32(TIMED_TEXT_FLAG_FRAME); - mFrameType = TIMED_TEXT_FLAG_FRAME; - } - - int32_t bDisc = 0; - accessUnit->meta()->findInt32("disc", &bDisc); - if(bDisc == 1) - { - DP_MSG_HIGH("sendTextPacket signal discontinuity"); - parcel.writeInt32(KEY_TEXT_DISCONTINUITY); - } - - // UPDATE TIMEDTEXT SAMPLE TEXT DATA - parcel.writeInt32(KEY_STRUCT_TEXT); - // write size of sample - parcel.writeInt32((int32_t)accessUnit->size()); - parcel.writeInt32((int32_t)accessUnit->size()); - // write sample payload - parcel.write((const uint8_t *)accessUnit->data(), accessUnit->size()); - - // UPDATE TIMEDTEXT SAMPLE PROPERTIES - int64_t mediaTimeUs = 0; - CHECK(accessUnit->meta()->findInt64("timeUs", &mediaTimeUs)); - parcel.writeInt32(KEY_START_TIME); - parcel.writeInt32((int32_t)(mediaTimeUs / 1000)); // convert micro sec to milli sec - - DP_MSG_HIGH("sendTextPacket Text Track Timestamp (%0.2f) sec",(double)mediaTimeUs / 1E6); - - int32_t height = 0; - if (accessUnit->meta()->findInt32("height", &height)) { - DP_MSG_LOW("sendTextPacket Height (%d)",height); - parcel.writeInt32(KEY_HEIGHT); - parcel.writeInt32(height); - } - - // width - int32_t width = 0; - if (accessUnit->meta()->findInt32("width", &width)) { - DP_MSG_LOW("sendTextPacket width (%d)",width); - parcel.writeInt32(KEY_WIDTH); - parcel.writeInt32(width); - } - - // Duration - int32_t duration = 0; - if (accessUnit->meta()->findInt32("duration", &duration)) { - DP_MSG_LOW("sendTextPacket duration (%d)",duration); - parcel.writeInt32(KEY_DURATION); - parcel.writeInt32(duration); - } - - // start offset - int32_t startOffset = 0; - if (accessUnit->meta()->findInt32("startoffset", &startOffset)) { - DP_MSG_LOW("sendTextPacket startOffset (%d)",startOffset); - parcel.writeInt32(KEY_START_OFFSET); - parcel.writeInt32(startOffset); - } - - // SubInfoSize - int32_t subInfoSize = 0; - if (accessUnit->meta()->findInt32("subSz", &subInfoSize)) { - DP_MSG_LOW("sendTextPacket subInfoSize (%d)",subInfoSize); - } - - // SubInfo - AString subInfo; - if (accessUnit->meta()->findString("subSi", &subInfo)) { - parcel.writeInt32(KEY_SUB_ATOM); - parcel.writeInt32(subInfoSize); - parcel.writeInt32(subInfoSize); - parcel.write((const uint8_t *)subInfo.c_str(), subInfoSize); - } - - notifyListener(MEDIA_TIMED_TEXT, 0, mFrameType, &parcel); -} - -void DashPlayer::getTrackName(int track, char* name) -{ - if( track == kAudio) - { - memset(name,0x00,6); - strlcpy(name, "audio",6); - } - else if( track == kVideo) - { - memset(name,0x00,6); - strlcpy(name, "video",6); - } - else if( track == kText) - { - memset(name,0x00,6); - strlcpy(name, "text",5); - } - else if (track == kTrackAll) - { - memset(name,0x00,6); - strlcpy(name, "all",4); - } -} - -void DashPlayer::prepareSource() -{ - mSourceNotify = new AMessage(kWhatSourceNotify ,this); - mQOENotify = new AMessage(kWhatQOE,this); - if (mSource != NULL) - { - mSource->setupSourceData(mSourceNotify,kTrackAll); - mSource->setupSourceData(mQOENotify,-1); - } -} - -status_t DashPlayer::dump(int fd, const Vector<String16> &/*args*/) -{ - if(mStats != NULL) { - mStats->setFileDescAndOutputStream(fd); - } - - return OK; -} - -void DashPlayer::setQCTimedTextListener(const bool val) -{ - mQCTimedTextListenerPresent = val; - DP_MSG_HIGH("QCTimedtextlistener turned %s", mQCTimedTextListenerPresent ? "ON" : "OFF"); -} - -void DashPlayer::processDeferredActions() { - while (!mDeferredActions.empty()) { - // We won't execute any deferred actions until we're no longer in - // an intermediate state, i.e. one more more decoders are currently - // flushing or shutting down. - - if (mRenderer != NULL) { - // There's an edge case where the renderer owns all output - // buffers and is paused, therefore the decoder will not read - // more input data and will never encounter the matching - // discontinuity. To avoid this, we resume the renderer. - - if (mFlushingAudio == AWAITING_DISCONTINUITY - || mFlushingVideo == AWAITING_DISCONTINUITY) { - mRenderer->resume(); - } - } - - if ((mFlushingAudio != NONE && mFlushingAudio != SHUT_DOWN) - || (mFlushingVideo != NONE && mFlushingVideo != SHUT_DOWN)) { - // We're currently flushing, postpone the reset until that's - // completed. - - DP_MSG_ERROR("postponing action mFlushingAudio=%d, mFlushingVideo=%d", - mFlushingAudio, mFlushingVideo); - - break; - } - - sp<Action> action = *mDeferredActions.begin(); - mDeferredActions.erase(mDeferredActions.begin()); - - action->execute(this); - } -} - -void DashPlayer::performSetSurface(const sp<Surface> &wrapper) { - DP_MSG_HIGH("performSetSurface"); - - mNativeWindow = wrapper; - - // XXX - ignore error from setVideoScalingMode for now - //setVideoScalingMode(mVideoScalingMode); - - if (mDriver != NULL) { - sp<DashPlayerDriver> driver = mDriver.promote(); - if (driver != NULL) { - driver->notifySetSurfaceComplete(); - } - } - - isSetSurfaceTexturePending = false; -} - -void DashPlayer::performScanSources() { - DP_MSG_ERROR("performScanSources"); - - //if (!mStarted) { - // return; - //} - - if (mAudioDecoder == NULL || mVideoDecoder == NULL) { - postScanSources(); - } -} - -void DashPlayer::performDecoderShutdown(bool audio, bool video) { - DP_MSG_ERROR("performDecoderShutdown audio=%d, video=%d", audio, video); - - if ((!audio || mAudioDecoder == NULL) - && (!video || mVideoDecoder == NULL)) { - return; - } - - //mTimeDiscontinuityPending = true; - - if (mFlushingAudio == NONE && (!audio || mAudioDecoder == NULL)) { - mFlushingAudio = FLUSHED; - } - - if (mFlushingVideo == NONE && (!video || mVideoDecoder == NULL)) { - mFlushingVideo = FLUSHED; - } - - if (audio && mAudioDecoder != NULL) { - flushDecoder(true /* audio */, true /* needShutdown */); - } - - if (video && mVideoDecoder != NULL) { - flushDecoder(false /* audio */, true /* needShutdown */); - } -} - - -/** @brief: Pushes blank frame to native window - * - * @return: NO_ERROR if frame pushed successfully to native window - * - */ -status_t DashPlayer::PushBlankBuffersToNativeWindow(sp<ANativeWindow> nativeWindow) { - status_t err = NO_ERROR; - ANativeWindowBuffer* anb = NULL; - int numBufs = 0; - int minUndequeuedBufs = 0; - - // We need to reconnect to the ANativeWindow as a CPU client to ensure that - // no frames get dropped by SurfaceFlinger assuming that these are video - // frames. - err = native_window_api_disconnect(nativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_api_connect(nativeWindow.get(), - NATIVE_WINDOW_API_CPU); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_connect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_set_buffers_dimensions(nativeWindow.get(), - 1, 1); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_dimensions failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_buffers_format(nativeWindow.get(), - HAL_PIXEL_FORMAT_RGBX_8888); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffers_format failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_scaling_mode(nativeWindow.get(), - NATIVE_WINDOW_SCALING_MODE_SCALE_TO_WINDOW); - if (err != NO_ERROR) { - ALOGE("error pushing blank_frames: set_scaling_mode failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = native_window_set_usage(nativeWindow.get(), - GRALLOC_USAGE_SW_WRITE_OFTEN); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_usage failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = nativeWindow->query(nativeWindow.get(), - NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBufs); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: MIN_UNDEQUEUED_BUFFERS query " - "failed: %s (%d)", strerror(-err), -err); - goto error; - } - - numBufs = minUndequeuedBufs + 1; - err = native_window_set_buffer_count(nativeWindow.get(), numBufs); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: set_buffer_count failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - // We push numBufs + 1 buffers to ensure that we've drawn into the same - // buffer twice. This should guarantee that the buffer has been displayed - // on the screen and then been replaced, so an previous video frames are - // guaranteed NOT to be currently displayed. - for (int i = 0; i < numBufs + 1; i++) { - int fenceFd = -1; - err = native_window_dequeue_buffer_and_wait(nativeWindow.get(), &anb); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: dequeueBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - sp<GraphicBuffer> buf(new GraphicBuffer(anb, false)); - - // Fill the buffer with the a 1x1 checkerboard pattern ;) - uint32_t* img = NULL; - err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img)); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: lock failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - *img = 0; - - err = buf->unlock(); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: unlock failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - err = nativeWindow->queueBuffer(nativeWindow.get(), - buf->getNativeBuffer(), -1); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: queueBuffer failed: %s (%d)", - strerror(-err), -err); - goto error; - } - - anb = NULL; - } - -error: - - if (err != NO_ERROR) { - // Clean up after an error. - if (anb != NULL) { - nativeWindow->cancelBuffer(nativeWindow.get(), anb, -1); - } - - native_window_api_disconnect(nativeWindow.get(), - NATIVE_WINDOW_API_CPU); - native_window_api_connect(nativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - - return err; - } else { - // Clean up after success. - err = native_window_api_disconnect(nativeWindow.get(), - NATIVE_WINDOW_API_CPU); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_disconnect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - err = native_window_api_connect(nativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - if (err != NO_ERROR) { - ALOGE("error pushing blank frames: api_connect failed: %s (%d)", - strerror(-err), -err); - return err; - } - - return NO_ERROR; - } -} - -} // namespace android diff --git a/dashplayer/DashPlayer.h b/dashplayer/DashPlayer.h deleted file mode 100644 index 28ee1fdd..00000000 --- a/dashplayer/DashPlayer.h +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DASH_PLAYER_H_ - -#define DASH_PLAYER_H_ - -#include "DashPlayerStats.h" -#include <media/MediaPlayerInterface.h> -#include <media/stagefright/foundation/AHandler.h> -#include <media/stagefright/foundation/ABuffer.h> -#include <media/stagefright/foundation/ADebug.h> -#include <media/stagefright/foundation/AMessage.h> -#include <gui/Surface.h> - - -#define KEY_QCTIMEDTEXT_LISTENER 6000 - -//Keys for playback modes -#define KEY_DASH_SEEK_EVENT 7001 -#define KEY_DASH_PAUSE_EVENT 7002 -#define KEY_DASH_RESUME_EVENT 7003 - -#define KEY_DASH_ADAPTION_PROPERTIES 8002 -#define KEY_DASH_MPD_QUERY 8003 -#define KEY_DASH_QOE_EVENT 8004 -#define KEY_DASH_QOE_PERIODIC_EVENT 8008 -//Keys to get and set mpd properties xml string -#define KEY_DASH_GET_ADAPTION_PROPERTIES 8010 -#define KEY_DASH_SET_ADAPTION_PROPERTIES 8011 - -//Key to query reposition range -#define KEY_DASH_REPOSITION_RANGE 9000 - -namespace android { - -struct MetaData; -struct DashPlayerDriver; - -enum { - kWhatQOE, - kWhatQOEPlay, - kWhatQOEStop, - kWhatQOESwitch, - kWhatQOEPeriodic, - }; - -struct DashPlayer : public AHandler { - DashPlayer(); - - void setUID(uid_t uid); - - void setDriver(const wp<DashPlayerDriver> &driver); - - void setDataSource(const sp<IStreamSource> &source); - - status_t setDataSource( - const char *url, const KeyedVector<String8, String8> *headers); - - void setDataSource(int fd, int64_t offset, int64_t length); - - void setVideoSurfaceTexture(const sp<IGraphicBufferProducer> &bufferProducer); - - void setAudioSink(const sp<MediaPlayerBase::AudioSink> &sink); - void start(); - - void pause(); - void resume(); - - // Will notify the driver through "notifyResetComplete" once finished. - void resetAsync(); - - // Will notify the driver through "notifySeekComplete" once finished. - void seekToAsync(int64_t seekTimeUs); - - status_t prepareAsync(); - status_t getParameter(int key, Parcel *reply); - status_t setParameter(int key, const Parcel &request); - status_t dump(int fd, const Vector<String16> &args); - - void setQCTimedTextListener(const bool val); - -public: - struct DASHHTTPLiveSource; - -protected: - virtual ~DashPlayer(); - - virtual void onMessageReceived(const sp<AMessage> &msg); - -private: - struct Decoder; - struct Renderer; - struct Source; - struct Action; - struct SimpleAction; - struct SetSurfaceAction; - struct ShutdownDecoderAction; - - enum { - // These keys must be in sync with the keys in QCTimedText.java - KEY_DISPLAY_FLAGS = 1, // int - KEY_STYLE_FLAGS = 2, // int - KEY_BACKGROUND_COLOR_RGBA = 3, // int - KEY_HIGHLIGHT_COLOR_RGBA = 4, // int - KEY_SCROLL_DELAY = 5, // int - KEY_WRAP_TEXT = 6, // int - KEY_START_TIME = 7, // int - KEY_STRUCT_BLINKING_TEXT_LIST = 8, // List<CharPos> - KEY_STRUCT_FONT_LIST = 9, // List<Font> - KEY_STRUCT_HIGHLIGHT_LIST = 10,// List<CharPos> - KEY_STRUCT_HYPER_TEXT_LIST = 11,// List<HyperText> - KEY_STRUCT_KARAOKE_LIST = 12,// List<Karaoke> - KEY_STRUCT_STYLE_LIST = 13,// List<Style> - KEY_STRUCT_TEXT_POS = 14,// TextPos - KEY_STRUCT_JUSTIFICATION = 15,// Justification - KEY_STRUCT_TEXT = 16,// Text - KEY_HEIGHT = 17, - KEY_WIDTH = 18, - KEY_DURATION = 19, - KEY_START_OFFSET = 20, - KEY_SUB_ATOM = 21, - KEY_TEXT_FORMAT = 22, - KEY_GLOBAL_SETTING = 101, - KEY_LOCAL_SETTING = 102, - KEY_START_CHAR = 103, - KEY_END_CHAR = 104, - KEY_FONT_ID = 105, - KEY_FONT_SIZE = 106, - KEY_TEXT_COLOR_RGBA = 107, - KEY_TEXT_EOS = 108, - KEY_TEXT_FLAG_TYPE = 109, - KEY_TEXT_DISCONTINUITY = 110, - }; - - enum { - kWhatSetDataSource = '=DaS', - kWhatSetVideoNativeWindow = '=NaW', - kWhatSetAudioSink = '=AuS', - kWhatStart = 'strt', - kWhatScanSources = 'scan', - kWhatVideoNotify = 'vidN', - kWhatAudioNotify = 'audN', - kWhatTextNotify = 'texN', - kWhatRendererNotify = 'renN', - kWhatReset = 'rset', - kWhatSeek = 'seek', - kWhatPause = 'paus', - kWhatResume = 'rsme', - kWhatPrepareAsync = 'pras', - kWhatIsPrepareDone = 'prdn', - kWhatSourceNotify = 'snfy', - }; - - enum { - kWhatBufferingStart = 'bfst', - kWhatBufferingEnd = 'bfen', - }; - - wp<DashPlayerDriver> mDriver; - bool mUIDValid; - uid_t mUID; - sp<Source> mSource; - sp<Surface> mNativeWindow; - sp<MediaPlayerBase::AudioSink> mAudioSink; - sp<Decoder> mVideoDecoder; - bool mVideoIsAVC; - sp<Decoder> mAudioDecoder; - sp<Decoder> mTextDecoder; - sp<Renderer> mRenderer; - - List<sp<Action> > mDeferredActions; - - bool mAudioEOS; - bool mVideoEOS; - - bool mScanSourcesPending; - bool isSetSurfaceTexturePending; - int32_t mScanSourcesGeneration; - bool mBufferingNotification; - - enum TrackName { - kVideo = 0, - kAudio, - kText, - kTrackAll, - }; - - enum FlushStatus { - NONE, - AWAITING_DISCONTINUITY, - FLUSHING_DECODER, - FLUSHING_DECODER_SHUTDOWN, - SHUTTING_DOWN_DECODER, - FLUSHED, - SHUT_DOWN, - }; - - //Should be in sync with QCTimedText.java - enum FrameFlags { - TIMED_TEXT_FLAG_FRAME = 0x00, - TIMED_TEXT_FLAG_CODEC_CONFIG, - TIMED_TEXT_FLAG_EOS, - TIMED_TEXT_FLAG_END = TIMED_TEXT_FLAG_EOS, - }; - - //Currently we only support SMPTE and CEA. Today sendTextPacket() has default parameter as SMPTE - enum TimedTextType { - TIMED_TEXT_SMPTE, - TIMED_TEXT_CEA, - TIMED_TEXT_UNKNOWN, - }; - - // Once the current flush is complete this indicates whether the - // notion of time has changed. - bool mTimeDiscontinuityPending; - - FlushStatus mFlushingAudio; - FlushStatus mFlushingVideo; - bool mResetInProgress; - bool mResetPostponed; - bool mSetVideoSize; - - int64_t mSkipRenderingAudioUntilMediaTimeUs; - int64_t mSkipRenderingVideoUntilMediaTimeUs; - - int64_t mVideoLateByUs; - - bool mPauseIndication; - - Mutex mLock; - - char *mTrackName; - sp<AMessage> mTextNotify; - sp<AMessage> mSourceNotify; - sp<AMessage> mQOENotify; - - int32_t mSRid; - - status_t instantiateDecoder(int track, sp<Decoder> *decoder); - - status_t feedDecoderInputData(int track, const sp<AMessage> &msg); - void renderBuffer(bool audio, const sp<AMessage> &msg); - - void notifyListener(int msg, int ext1, int ext2, const Parcel *obj=NULL); - - void finishFlushIfPossible(); - - void flushDecoder(bool audio, bool needShutdown); - - static bool IsFlushingState(FlushStatus state, bool *needShutdown = NULL); - - void finishReset(); - void postScanSources(); - - sp<Source> LoadCreateSource(const char * uri, const KeyedVector<String8, - String8> *headers, bool uidValid, uid_t uid); - - void postIsPrepareDone(); - - // for qualcomm statistics profiling - sp<DashPlayerStats> mStats; - - void sendTextPacket(sp<ABuffer> accessUnit, status_t err, DashPlayer::TimedTextType eTimedTextType = TIMED_TEXT_SMPTE); - void getTrackName(int track, char* name); - void prepareSource(); - - void processDeferredActions(); - - void performDecoderShutdown(bool audio, bool video); - void performScanSources(); - void performSetSurface(const sp<Surface> &wrapper); - void writeTrackInfo(Parcel* reply, const sp<AMessage> format) const; - status_t PushBlankBuffersToNativeWindow(sp<ANativeWindow> nativeWindow); - - int mLogLevel; - bool mTimedTextCEAPresent; - - //Set and reset in cases of seek/resume-out-of-tsb to signal discontinuity in CEA timedtextsamples - bool mTimedTextCEASamplesDisc; - - //Tells if app registered for a QCTimedText Listener. If not registered do not send text samples above. - bool mQCTimedTextListenerPresent; - - int32_t mCurrentWidth; - int32_t mCurrentHeight; - int32_t mColorFormat; - - DISALLOW_EVIL_CONSTRUCTORS(DashPlayer); -}; - -} // namespace android - -#endif // DASH_PLAYER_H_ diff --git a/dashplayer/DashPlayerDecoder.cpp b/dashplayer/DashPlayerDecoder.cpp deleted file mode 100644 index ec66c1db..00000000 --- a/dashplayer/DashPlayerDecoder.cpp +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "DashPlayerDecoder" - -#include "DashPlayerDecoder.h" -#include <media/ICrypto.h> -#include "ESDS.h" -#include "QCMediaDefs.h" -#include "QCMetaData.h" -#include <media/stagefright/MediaCodec.h> -#include <media/stagefright/MediaDefs.h> -#include <media/stagefright/MediaErrors.h> -#include <media/stagefright/MetaData.h> -#include <media/stagefright/Utils.h> -#include <cutils/properties.h> -#include <utils/Log.h> - -//Smooth streaming settings, -//Max resolution 1080p -#define MAX_WIDTH 1920 -#define MAX_HEIGHT 1080 - -#define DPD_MSG_ERROR(...) ALOGE(__VA_ARGS__) -#define DPD_MSG_HIGH(...) if(mLogLevel >= 1){ALOGE(__VA_ARGS__);} -#define DPD_MSG_MEDIUM(...) if(mLogLevel >= 2){ALOGE(__VA_ARGS__);} -#define DPD_MSG_LOW(...) if(mLogLevel >= 3){ALOGE(__VA_ARGS__);} - -namespace android { - -DashPlayer::Decoder::Decoder( - const sp<AMessage> ¬ify, - const sp<Surface> &nativeWindow) - : mNotify(notify), - mNativeWindow(nativeWindow), - mLogLevel(0), - mBufferGeneration(0), - mComponentName("decoder") { - // Every decoder has its own looper because MediaCodec operations - // are blocking, but DashPlayer needs asynchronous operations. - mDecoderLooper = new ALooper; - mDecoderLooper->setName("DashPlayerDecoder"); - mDecoderLooper->start(false, false, ANDROID_PRIORITY_AUDIO); - - mCodecLooper = new ALooper; - mCodecLooper->setName("DashPlayerDecoder-MC"); - mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); - - char property_value[PROPERTY_VALUE_MAX] = {0}; - property_get("persist.dash.debug.level", property_value, NULL); - - if(*property_value) { - mLogLevel = atoi(property_value); - } -} - -DashPlayer::Decoder::~Decoder() { -} - -/** @brief: configure mediacodec - * - * @return: void - * - */ -void DashPlayer::Decoder::onConfigure(const sp<AMessage> &format) { - CHECK(mCodec == NULL); - - ++mBufferGeneration; - - AString mime; - CHECK(format->findString("mime", &mime)); - - /* - sp<Surface> surface = NULL; - if (mNativeWindow != NULL) { - surface = mNativeWindow->getSurfaceTextureClient(); - } - */ - - mComponentName = mime; - mComponentName.append(" decoder"); - DPD_MSG_HIGH("[%s] onConfigure (surface=%p)", mComponentName.c_str(), mNativeWindow.get()); - - mCodec = MediaCodec::CreateByType(mCodecLooper, mime.c_str(), false /* encoder */); - if (mCodec == NULL) { - DPD_MSG_ERROR("Failed to create %s decoder", mime.c_str()); - handleError(UNKNOWN_ERROR); - return; - } - - mCodec->getName(&mComponentName); - - status_t err; - if (mNativeWindow != NULL) { - // disconnect from surface as MediaCodec will reconnect - err = native_window_api_disconnect( - mNativeWindow.get(), NATIVE_WINDOW_API_MEDIA); - // We treat this as a warning, as this is a preparatory step. - // Codec will try to connect to the surface, which is where - // any error signaling will occur. - ALOGW_IF(err != OK, "failed to disconnect from surface: %d", err); - } - err = mCodec->configure( - format, mNativeWindow, NULL /* crypto */, 0 /* flags */); - if (err != OK) { - DPD_MSG_ERROR("Failed to configure %s decoder (err=%d)", mComponentName.c_str(), err); - handleError(err); - return; - } - // the following should work in configured state - CHECK_EQ((status_t)OK, mCodec->getOutputFormat(&mOutputFormat)); - CHECK_EQ((status_t)OK, mCodec->getInputFormat(&mInputFormat)); - - err = mCodec->start(); - if (err != OK) { - DPD_MSG_ERROR("Failed to start %s decoder (err=%d)", mComponentName.c_str(), err); - handleError(err); - return; - } - - // the following should work after start - CHECK_EQ((status_t)OK, mCodec->getInputBuffers(&mInputBuffers)); - CHECK_EQ((status_t)OK, mCodec->getOutputBuffers(&mOutputBuffers)); - DPD_MSG_HIGH("[%s] got %zu input and %zu output buffers", - mComponentName.c_str(), - mInputBuffers.size(), - mOutputBuffers.size()); - - requestCodecNotification(); -} - -/** @brief: Register activity notification to mediacodec - * - * @return: void - * - */ -void DashPlayer::Decoder::requestCodecNotification() { - if (mCodec != NULL) { - sp<AMessage> reply = new AMessage(kWhatCodecNotify, this); - reply->setInt32("generation", mBufferGeneration); - mCodec->requestActivityNotification(reply); - } - } - -bool DashPlayer::Decoder::isStaleReply(const sp<AMessage> &msg) { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - return generation != mBufferGeneration; - } - -void DashPlayer::Decoder::init() { - mDecoderLooper->registerHandler(this); -} - -/** @brief: configure decoder - * - * @return: void - * - */ -void DashPlayer::Decoder::configure(const sp<MetaData> &meta) { - sp<AMessage> msg = new AMessage(kWhatConfigure, this); - sp<AMessage> format = makeFormat(meta); - msg->setMessage("format", format); - msg->post(); -} - -/** @brief: notify decoder error to dashplayer - * - * @return: void - * - */ -void DashPlayer::Decoder::handleError(int32_t err) -{ - DPD_MSG_HIGH("[%s] handleError : %d", mComponentName.c_str() , err); - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatError); - notify->setInt32("err", err); - notify->post(); -} - -/** @brief: send input buffer from codec to dashplayer - * - * @return: true if valid buffer found - * - */ -bool DashPlayer::Decoder::handleAnInputBuffer() { - size_t bufferIx = -1; - status_t res = mCodec->dequeueInputBuffer(&bufferIx); - DPD_MSG_HIGH("[%s] dequeued input: %d", - mComponentName.c_str(), res == OK ? (int)bufferIx : res); - if (res != OK) { - if (res != -EAGAIN) { - handleError(res); - } - return false; - } - - CHECK_LT(bufferIx, mInputBuffers.size()); - - sp<AMessage> reply = new AMessage(kWhatInputBufferFilled, this); - reply->setSize("buffer-ix", bufferIx); - reply->setInt32("generation", mBufferGeneration); - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatFillThisBuffer); - notify->setBuffer("buffer", mInputBuffers[bufferIx]); - notify->setMessage("reply", reply); - notify->post(); - return true; -} - -/** @brief: Send input buffer to decoder - * - * @return: void - * - */ -void android::DashPlayer::Decoder::onInputBufferFilled(const sp<AMessage> &msg) { - size_t bufferIx; - CHECK(msg->findSize("buffer-ix", &bufferIx)); - CHECK_LT(bufferIx, mInputBuffers.size()); - sp<ABuffer> codecBuffer = mInputBuffers[bufferIx]; - - sp<ABuffer> buffer; - bool hasBuffer = msg->findBuffer("buffer", &buffer); - if (buffer == NULL /* includes !hasBuffer */) { - int32_t streamErr = ERROR_END_OF_STREAM; - CHECK(msg->findInt32("err", &streamErr) || !hasBuffer); - - if (streamErr == OK) { - /* buffers are returned to hold on to */ - return; - } - - // attempt to queue EOS - status_t err = mCodec->queueInputBuffer( - bufferIx, - 0, - 0, - 0, - MediaCodec::BUFFER_FLAG_EOS); - if (streamErr == ERROR_END_OF_STREAM && err != OK) { - streamErr = err; - // err will not be ERROR_END_OF_STREAM - } - - if (streamErr != ERROR_END_OF_STREAM) { - handleError(streamErr); - } - } else { - int64_t timeUs = 0; - uint32_t flags = 0; - CHECK(buffer->meta()->findInt64("timeUs", &timeUs)); - - int32_t eos; - // we do not expect CODECCONFIG or SYNCFRAME for decoder - if (buffer->meta()->findInt32("eos", &eos) && eos) { - flags |= MediaCodec::BUFFER_FLAG_EOS; - } - - DPD_MSG_MEDIUM("Input buffer:[%s]: %p", mComponentName.c_str(), buffer->data()); - - // copy into codec buffer - if (buffer != codecBuffer) { - CHECK_LE(buffer->size(), codecBuffer->capacity()); - codecBuffer->setRange(0, buffer->size()); - memcpy(codecBuffer->data(), buffer->data(), buffer->size()); - } - - status_t err = mCodec->queueInputBuffer( - bufferIx, - codecBuffer->offset(), - codecBuffer->size(), - timeUs, - flags); - if (err != OK) { - DPD_MSG_ERROR("Failed to queue input buffer for %s (err=%d)", - mComponentName.c_str(), err); - handleError(err); - } - } -} - -/** @brief: dequeue out buffer from mediacodec and send it to renderer - * - * @return: void - * - */ -bool DashPlayer::Decoder::handleAnOutputBuffer() { - size_t bufferIx = -1; - size_t offset; - size_t size; - int64_t timeUs; - uint32_t flags; - status_t res = mCodec->dequeueOutputBuffer( - &bufferIx, &offset, &size, &timeUs, &flags); - - if (res != OK) { - DPD_MSG_HIGH("[%s] dequeued output: %d", mComponentName.c_str(), res); - } else { - DPD_MSG_HIGH("[%s] dequeued output: %d (time=%lld flags=%u)", - mComponentName.c_str(), (int)bufferIx, timeUs, flags); - } - - if (res == INFO_OUTPUT_BUFFERS_CHANGED) { - res = mCodec->getOutputBuffers(&mOutputBuffers); - if (res != OK) { - DPD_MSG_ERROR("Failed to get output buffers for %s after INFO event (err=%d)", - mComponentName.c_str(), res); - handleError(res); - return false; - } - // DashPlayer ignores this - return true; - } else if (res == INFO_FORMAT_CHANGED) { - sp<AMessage> format = new AMessage(); - res = mCodec->getOutputFormat(&format); - if (res != OK) { - DPD_MSG_ERROR("Failed to get output format for %s after INFO event (err=%d)", - mComponentName.c_str(), res); - handleError(res); - return false; - } - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatOutputFormatChanged); - notify->setMessage("format", format); - notify->post(); - return true; - } else if (res == INFO_DISCONTINUITY) { - // nothing to do - return true; - } else if (res != OK) { - if (res != -EAGAIN) { - handleError(res); - } - return false; - } - - // FIXME: This should be handled after rendering is complete, - // but Renderer needs it now - if (flags & MediaCodec::BUFFER_FLAG_EOS) { - DPD_MSG_ERROR("queueing eos [%s]", mComponentName.c_str()); - - status_t err; - err = mCodec->releaseOutputBuffer(bufferIx); - if (err != OK) { - DPD_MSG_ERROR("failed to release output buffer for %s (err=%d)", - mComponentName.c_str(), err); - handleError(err); - } - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatEOS); - notify->setInt32("err", ERROR_END_OF_STREAM); - notify->post(); - return true; - } - - CHECK_LT(bufferIx, mOutputBuffers.size()); - sp<ABuffer> buffer = mOutputBuffers[bufferIx]; - buffer->setRange(offset, size); - - sp<RefBase> obj; - sp<GraphicBuffer> graphicBuffer; - if (buffer->meta()->findObject("graphic-buffer", &obj)) { - graphicBuffer = static_cast<GraphicBuffer*>(obj.get()); - } - - buffer->meta()->clear(); - buffer->meta()->setInt64("timeUs", timeUs); - if (flags & MediaCodec::BUFFER_FLAG_EOS) { - buffer->meta()->setInt32("eos", true); - } - // we do not expect CODECCONFIG or SYNCFRAME for decoder - - sp<AMessage> reply = new AMessage(kWhatRenderBuffer, this); - reply->setSize("buffer-ix", bufferIx); - reply->setInt32("generation", mBufferGeneration); - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatDrainThisBuffer); - - if(flags & MediaCodec::BUFFER_FLAG_EXTRADATA) { - buffer->meta()->setInt32("extradata", 1); - } - - buffer->meta()->setObject("graphic-buffer", graphicBuffer); - notify->setBuffer("buffer", buffer); - notify->setMessage("reply", reply); - notify->post(); - - return true; -} - -/** @brief: Give buffer to mediacodec for rendering - * - * @return: void - * - */ -void DashPlayer::Decoder::onRenderBuffer(const sp<AMessage> &msg) { - status_t err; - int32_t render; - size_t bufferIx; - CHECK(msg->findSize("buffer-ix", &bufferIx)); - if (msg->findInt32("render", &render) && render) { - err = mCodec->renderOutputBufferAndRelease(bufferIx); - } else { - err = mCodec->releaseOutputBuffer(bufferIx); - } - if (err != OK) { - DPD_MSG_ERROR("failed to release output buffer for %s (err=%d)", - mComponentName.c_str(), err); - handleError(err); - } - } - -/** @brief: notify decoder flush complete to dashplayer - * - * @return: void - * - */ -void DashPlayer::Decoder::onFlush() { - status_t err = OK; - if (mCodec != NULL) { - err = mCodec->flush(); - ++mBufferGeneration; - } - - if (err != OK) { - DPD_MSG_ERROR("failed to flush %s (err=%d)", mComponentName.c_str(), err); - handleError(err); - // finish with posting kWhatFlushCompleted. - } - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatFlushCompleted); - notify->post(); -} - -/** @brief: notify decoder shutdown complete to dashplayer - * - * @return: void - * - */ -void DashPlayer::Decoder::onShutdown() { - status_t err = OK; - if (mCodec != NULL) { - err = mCodec->release(); - mCodec = NULL; - ++mBufferGeneration; - - if (mNativeWindow != NULL) { - // reconnect to surface as MediaCodec disconnected from it - status_t error = - native_window_api_connect( - mNativeWindow.get(), - NATIVE_WINDOW_API_MEDIA); - ALOGW_IF(error != NO_ERROR, - "[%s] failed to connect to native window, error=%d", - mComponentName.c_str(), error); - } - mComponentName = "decoder"; - } - - if (err != OK) { - DPD_MSG_ERROR("failed to release %s (err=%d)", mComponentName.c_str(), err); - handleError(err); - // finish with posting kWhatShutdownCompleted. - } - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatShutdownCompleted); - notify->post(); -} - -/** @brief: message handler to handle dashplayer/mediacodec messages - * - * @return: void - * - */ -void DashPlayer::Decoder::onMessageReceived(const sp<AMessage> &msg) { - DPD_MSG_HIGH("[%s] onMessage: %s", mComponentName.c_str(), msg->debugString().c_str()); - - switch (msg->what()) { - case kWhatConfigure: - { - sp<AMessage> format; - CHECK(msg->findMessage("format", &format)); - onConfigure(format); - break; - } - - case kWhatCodecNotify: - { - if (!isStaleReply(msg)) { - while (handleAnInputBuffer()) { - } - - while (handleAnOutputBuffer()) { - } - } - - requestCodecNotification(); - break; - } - - case kWhatInputBufferFilled: - { - if (!isStaleReply(msg)) { - onInputBufferFilled(msg); - } - break; - } - - case kWhatRenderBuffer: - { - if (!isStaleReply(msg)) { - onRenderBuffer(msg); - } - break; - } - - case kWhatFlush: - { - onFlush(); - break; - } - - case kWhatShutdown: - { - onShutdown(); - break; - } - - default: - TRESPASS(); - break; - } -} - -void DashPlayer::Decoder::signalFlush() { - (new AMessage(kWhatFlush, this))->post(); -} - -void DashPlayer::Decoder::signalResume() { - // nothing to do -} - -void DashPlayer::Decoder::initiateShutdown() { - (new AMessage(kWhatShutdown, this))->post(); -} - - -/** @brief: convert input metadat into AMessage format - * - * @return: input format value in AMessage - * - */ -sp<AMessage> DashPlayer::Decoder::makeFormat(const sp<MetaData> &meta) { - sp<AMessage> msg; - CHECK_EQ(convertMetaDataToMessage(meta, &msg), (status_t)OK); - const char *mime; - CHECK(meta->findCString(kKeyMIMEType, &mime)); - - if(!strncasecmp(mime, "video/", strlen("video/"))){ - msg->setInt32("max-height", MAX_HEIGHT); - msg->setInt32("max-width", MAX_WIDTH); - msg->setInt32("enable-extradata-user", 1); - - // Below property requie to set to prefer adaptive playback - // msg->setInt32("prefer-adaptive-playback", 1); - } - - return msg; -} - -} // namespace android - diff --git a/dashplayer/DashPlayerDecoder.h b/dashplayer/DashPlayerDecoder.h deleted file mode 100644 index 9e8167d3..00000000 --- a/dashplayer/DashPlayerDecoder.h +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DASHPLAYER_DECODER_H_ - -#define DASHPLAYER_DECODER_H_ - -#include "DashPlayerRenderer.h" -#include "DashPlayer.h" -#include <media/stagefright/foundation/AHandler.h> - -namespace android { - -struct ABuffer; -struct MediaCodec; - -struct DashPlayer::Decoder : public AHandler { - Decoder(const sp<AMessage> ¬ify, - const sp<Surface> &nativeWindow = NULL); - - void configure(const sp<MetaData> &meta); - void init(); - - void signalFlush(); - void signalResume(); - void initiateShutdown(); - - - enum { - kWhatFillThisBuffer = 'flTB', - kWhatDrainThisBuffer = 'drTB', - kWhatOutputFormatChanged = 'fmtC', - kWhatFlushCompleted = 'flsC', - kWhatShutdownCompleted = 'shDC', - kWhatEOS = 'eos ', - kWhatError = 'err ', - }; - -protected: - virtual ~Decoder(); - - virtual void onMessageReceived(const sp<AMessage> &msg); - -private: - enum { - kWhatCodecNotify = 'cdcN', - kWhatConfigure = 'conf', - kWhatInputBufferFilled = 'inpF', - kWhatRenderBuffer = 'rndr', - kWhatFlush = 'flus', - kWhatShutdown = 'shuD', - }; - - sp<AMessage> mNotify; - sp<Surface> mNativeWindow; - - sp<AMessage> mInputFormat; - sp<AMessage> mOutputFormat; - sp<MediaCodec> mCodec; - sp<ALooper> mCodecLooper; - sp<ALooper> mDecoderLooper; - - Vector<sp<ABuffer> > mInputBuffers; - Vector<sp<ABuffer> > mOutputBuffers; - - void handleError(int32_t err); - bool handleAnInputBuffer(); - bool handleAnOutputBuffer(); - - void requestCodecNotification(); - bool isStaleReply(const sp<AMessage> &msg); - - int mLogLevel; - - sp<AMessage> makeFormat(const sp<MetaData> &meta); - - void onConfigure(const sp<AMessage> &format); - void onFlush(); - void onInputBufferFilled(const sp<AMessage> &msg); - void onRenderBuffer(const sp<AMessage> &msg); - void onShutdown(); - - int32_t mBufferGeneration; - AString mComponentName; - - - DISALLOW_EVIL_CONSTRUCTORS(Decoder); -}; - -} // namespace android - -#endif // DASHPLAYER_DECODER_H_ diff --git a/dashplayer/DashPlayerDriver.cpp b/dashplayer/DashPlayerDriver.cpp deleted file mode 100644 index 2d8eddfa..00000000 --- a/dashplayer/DashPlayerDriver.cpp +++ /dev/null @@ -1,503 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "DashPlayerDriver" - -#include "DashPlayerDriver.h" -#include "DashPlayer.h" -#include <media/stagefright/foundation/ALooper.h> -#include <cutils/properties.h> -#include <utils/Log.h> - -#define DPD_MSG_ERROR(...) ALOGE(__VA_ARGS__) -#define DPD_MSG_HIGH(...) if(mLogLevel >= 1){ALOGE(__VA_ARGS__);} -#define DPD_MSG_MEDIUM(...) if(mLogLevel >= 2){ALOGE(__VA_ARGS__);} -#define DPD_MSG_LOW(...) if(mLogLevel >= 3){ALOGE(__VA_ARGS__);} - -namespace android { - -DashPlayerDriver::DashPlayerDriver() - : mResetInProgress(false), - mSetSurfaceInProgress(false), - mDurationUs(-1), - mPositionUs(-1), - mLooper(new ALooper), - mState(UNINITIALIZED), - mAtEOS(false), - mStartupSeekTimeUs(-1), - mLogLevel(0){ - mLooper->setName("DashPlayerDriver Looper"); - - mLooper->start( - false, /* runOnCallingThread */ - true, /* canCallJava */ - PRIORITY_AUDIO); - - mPlayer = new DashPlayer; - mLooper->registerHandler(mPlayer); - - mPlayer->setDriver(this); - - char property_value[PROPERTY_VALUE_MAX] = {0}; - property_get("persist.dash.debug.level", property_value, NULL); - - if(*property_value) { - mLogLevel = atoi(property_value); - } - -} - -DashPlayerDriver::~DashPlayerDriver() { - mLooper->stop(); - mLooper->unregisterHandler(mPlayer->id()); -} - -status_t DashPlayerDriver::initCheck() { - return OK; -} - -status_t DashPlayerDriver::setUID(uid_t uid) { - mPlayer->setUID(uid); - - return OK; -} - -status_t DashPlayerDriver::setDataSource(const sp<IMediaHTTPService> &/*httpService*/, - const char *url, const KeyedVector<String8, String8> *headers) { - CHECK_EQ((int)mState, (int)UNINITIALIZED); - - status_t ret = mPlayer->setDataSource(url, headers); - - mState = STOPPED; - - return ret; -} - -status_t DashPlayerDriver::setDataSource(int fd, int64_t offset, int64_t length) { - CHECK_EQ((int)mState, (int)UNINITIALIZED); - - mPlayer->setDataSource(fd, offset, length); - - mState = STOPPED; - - return OK; -} - -status_t DashPlayerDriver::setDataSource(const sp<IStreamSource> &source) { - CHECK_EQ((int)mState, (int)UNINITIALIZED); - - mPlayer->setDataSource(source); - - mState = STOPPED; - - return OK; -} - -status_t DashPlayerDriver::setVideoSurfaceTexture( - const sp<IGraphicBufferProducer> &bufferProducer) { - Mutex::Autolock autoLock(mLock); - - if (mResetInProgress) { - return INVALID_OPERATION; - } - - DPD_MSG_ERROR("DashPlayerDriver::setVideoSurfaceTexture call and block"); - - mSetSurfaceInProgress = true; - - mPlayer->setVideoSurfaceTexture(bufferProducer); - - while (mSetSurfaceInProgress) { - mCondition.wait(mLock); - } - - return OK; -} - -status_t DashPlayerDriver::prepare() { - sendEvent(MEDIA_SET_VIDEO_SIZE, 0, 0); - return OK; -} - -status_t DashPlayerDriver::prepareAsync() { - status_t err = (status_t)UNKNOWN_ERROR; - if (mPlayer != NULL) { - err = mPlayer->prepareAsync(); - } - - if (err == OK) { - err = prepare(); - notifyListener(MEDIA_PREPARED); - } else if (err == -EWOULDBLOCK) { - // this case only happens for DASH - return OK; - } - return err; -} - -status_t DashPlayerDriver::start() { - switch (mState) { - case UNINITIALIZED: - return INVALID_OPERATION; - case STOPPED: - { - mAtEOS = false; - mPlayer->start(); - - if (mStartupSeekTimeUs >= 0) { - if (mStartupSeekTimeUs == 0) { - notifySeekComplete(); - } else { - mPlayer->seekToAsync(mStartupSeekTimeUs); - } - - mStartupSeekTimeUs = -1; - } - - break; - } - case PLAYING: - return OK; - default: - { - CHECK_EQ((int)mState, (int)PAUSED); - mPlayer->resume(); - break; - } - } - - mState = PLAYING; - - return OK; -} - -status_t DashPlayerDriver::stop() { - return pause(); -} - -status_t DashPlayerDriver::pause() { - switch (mState) { - case UNINITIALIZED: - return INVALID_OPERATION; - case STOPPED: - return OK; - case PLAYING: - mPlayer->pause(); - break; - default: - { - CHECK_EQ((int)mState, (int)PAUSED); - return OK; - } - } - - mState = PAUSED; - - return OK; -} - -bool DashPlayerDriver::isPlaying() { - return mState == PLAYING && !mAtEOS; -} - -status_t DashPlayerDriver::seekTo(int msec) { - int64_t seekTimeUs = msec * 1000ll; - - switch (mState) { - case UNINITIALIZED: - return INVALID_OPERATION; - case STOPPED: - { - mStartupSeekTimeUs = seekTimeUs; - break; - } - case PLAYING: - case PAUSED: - { - mAtEOS = false; - mPlayer->seekToAsync(seekTimeUs); - break; - } - - default: - TRESPASS(); - break; - } - - return OK; -} - -status_t DashPlayerDriver::getCurrentPosition(int *msec) { - Mutex::Autolock autoLock(mLock); - - if (mPositionUs < 0) { - *msec = 0; - } else { - *msec = (int)((mPositionUs + 500ll) / 1000); - } - - return OK; -} - -status_t DashPlayerDriver::getDuration(int *msec) { - Mutex::Autolock autoLock(mLock); - - if (mDurationUs < 0) { - *msec = 0; - } else { - *msec = (int)((mDurationUs + 500ll) / 1000); - } - - return OK; -} - -status_t DashPlayerDriver::reset() { - Mutex::Autolock autoLock(mLock); - mResetInProgress = true; - - mPlayer->resetAsync(); - - while (mResetInProgress) { - mCondition.wait(mLock); - } - - mDurationUs = -1; - mPositionUs = -1; - mState = UNINITIALIZED; - mStartupSeekTimeUs = -1; - - return OK; -} - -status_t DashPlayerDriver::setLooping(int /*loop*/) { - return INVALID_OPERATION; -} - -player_type DashPlayerDriver::playerType() { - return DASH_PLAYER; -} - -void DashPlayerDriver::setQCTimedTextListener(const bool val) { - mPlayer->setQCTimedTextListener(val); -} - -status_t DashPlayerDriver::invoke(const Parcel &request, Parcel *reply) { - status_t ret = INVALID_OPERATION; - - if (reply == NULL) { - DPD_MSG_ERROR("reply is a NULL pointer"); - return BAD_VALUE; - } - - int32_t methodId; - ret = request.readInt32(&methodId); - if (ret != OK) { - DPD_MSG_ERROR("Failed to retrieve the requested method to invoke"); - return ret; - } - - switch (methodId) { - case KEY_DASH_GET_ADAPTION_PROPERTIES: - { - DPD_MSG_HIGH("calling KEY_DASH_GET_ADAPTION_PROPERTIES"); - ret = getParameter(methodId,reply); - break; - } - case KEY_DASH_SET_ADAPTION_PROPERTIES: - { - DPD_MSG_HIGH("calling KEY_DASH_SET_ADAPTION_PROPERTIES"); - int32_t val = 0; - ret = setParameter(methodId,request); - val = (ret == OK)? 1:0; - reply->setDataPosition(0); - reply->writeInt32(val); - break; - } - case KEY_DASH_MPD_QUERY: - { - DPD_MSG_HIGH("calling KEY_DASH_MPD_QUERY"); - ret = getParameter(methodId,reply); - break; - } - - case KEY_DASH_QOE_EVENT: - DPD_MSG_HIGH("calling KEY_DASH_QOE_EVENT"); - ret = setParameter(methodId,request); - break; - - case KEY_DASH_QOE_PERIODIC_EVENT: - DPD_MSG_HIGH("calling KEY_DASH_QOE_PERIODIC_EVENT"); - ret = getParameter(methodId,reply); - break; - - case KEY_DASH_REPOSITION_RANGE: - DPD_MSG_HIGH("calling KEY_DASH_REPOSITION_RANGE"); - ret = getParameter(methodId,reply); - break; - - case KEY_DASH_SEEK_EVENT: - { - DPD_MSG_HIGH("calling KEY_DASH_SEEK_EVENT seekTo()"); - int32_t msec; - ret = request.readInt32(&msec); - if (ret != OK) - { - DPD_MSG_ERROR("Invoke: invalid seek value"); - } - else - { - ret = seekTo(msec); - int32_t val = (ret == OK)? 1:0; - reply->setDataPosition(0); - reply->writeInt32(val); - } - break; - } - - case KEY_DASH_PAUSE_EVENT: - { - DPD_MSG_HIGH("calling KEY_DASH_PAUSE_EVENT pause()"); - ret = pause(); - int32_t val = (ret == OK)? 1:0; - reply->setDataPosition(0); - reply->writeInt32(val); - break; - } - - case KEY_DASH_RESUME_EVENT: - { - DPD_MSG_HIGH("calling KEY_DASH_RESUME_EVENT pause()"); - ret = start(); - int32_t val = (ret == OK)? 1:0; - reply->setDataPosition(0); - reply->writeInt32(val); - break; - } - - case KEY_QCTIMEDTEXT_LISTENER: - { - DPD_MSG_HIGH("calling KEY_QCTIMEDTEXT_LISTENER"); - - int32_t val = 0; - ret = request.readInt32(&val); - if (ret != OK) - { - DPD_MSG_ERROR("Invoke KEY_QCTIMEDTEXT_LISTENER: invalid val"); - } - else - { - bool bVal = (val == 1)? true:false; - setQCTimedTextListener(bVal); - reply->setDataPosition(0); - reply->writeInt32(1); - } - break; - } - - case INVOKE_ID_GET_TRACK_INFO: - { - // Ignore the invoke call for INVOKE_ID_GET_TRACK_INFO with success return code - // to avoid mediaplayer java exception - DPD_MSG_HIGH("Calling INVOKE_ID_GET_TRACK_INFO to invoke"); - ret = getParameter(methodId,reply); - break; - } - - default: - { - DPD_MSG_ERROR("Invoke:unHandled requested method%d",methodId); - ret = INVALID_OPERATION; - break; - } - } - - return ret; -} - -void DashPlayerDriver::setAudioSink(const sp<AudioSink> &audioSink) { - mPlayer->setAudioSink(audioSink); -} - -status_t DashPlayerDriver::setParameter(int key, const Parcel &request) { - status_t err = (status_t)UNKNOWN_ERROR; - if (mPlayer != NULL) - { - err = mPlayer->setParameter(key, request); - } - return err; -} - -status_t DashPlayerDriver::getParameter(int key, Parcel *reply) { - - status_t err = (status_t)UNKNOWN_ERROR; - if (mPlayer != NULL) - { - err = mPlayer->getParameter(key, reply); - } - return err; -} - -status_t DashPlayerDriver::getMetadata( - const media::Metadata::Filter& /*ids*/, Parcel * /*records*/) { - return INVALID_OPERATION; -} - -void DashPlayerDriver::notifyResetComplete() { - Mutex::Autolock autoLock(mLock); - CHECK(mResetInProgress); - mResetInProgress = false; - mCondition.broadcast(); -} - -void DashPlayerDriver::notifySetSurfaceComplete() { - Mutex::Autolock autoLock(mLock); - CHECK(mSetSurfaceInProgress); - mSetSurfaceInProgress = false; - DPD_MSG_ERROR("DashPlayerDriver::notifySetSurfaceComplete done"); - mCondition.broadcast(); -} - -void DashPlayerDriver::notifyDuration(int64_t durationUs) { - Mutex::Autolock autoLock(mLock); - mDurationUs = durationUs; -} - -void DashPlayerDriver::notifyPosition(int64_t positionUs) { - Mutex::Autolock autoLock(mLock); - mPositionUs = positionUs; -} - -void DashPlayerDriver::notifySeekComplete() { - notifyListener(MEDIA_SEEK_COMPLETE); -} - -status_t DashPlayerDriver::dump(int fd, const Vector<String16> &args) const { - if(mPlayer != NULL) { - mPlayer->dump(fd, args); - } - return OK; -} - -void DashPlayerDriver::notifyListener(int msg, int ext1, int ext2, const Parcel *obj) { - if (msg == MEDIA_PLAYBACK_COMPLETE || msg == MEDIA_ERROR) { - mAtEOS = true; - } - - sendEvent(msg, ext1, ext2, obj); -} - -} // namespace android diff --git a/dashplayer/DashPlayerDriver.h b/dashplayer/DashPlayerDriver.h deleted file mode 100644 index 3949b682..00000000 --- a/dashplayer/DashPlayerDriver.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include <media/MediaPlayerInterface.h> -#include <media/stagefright/foundation/ABase.h> - -namespace android { - -struct ALooper; -struct DashPlayer; - -struct DashPlayerDriver : public MediaPlayerInterface { - DashPlayerDriver(); - - virtual status_t initCheck(); - - virtual status_t setUID(uid_t uid); - - virtual status_t setDataSource(const sp<IMediaHTTPService> &httpService, - const char *url, const KeyedVector<String8, String8> *headers); - - virtual status_t setDataSource(int fd, int64_t offset, int64_t length); - - virtual status_t setDataSource(const sp<IStreamSource> &source); - - virtual status_t setVideoSurfaceTexture( - const sp<IGraphicBufferProducer> &bufferProducer); - - virtual status_t prepare(); - virtual status_t prepareAsync(); - virtual status_t start(); - virtual status_t stop(); - virtual status_t pause(); - virtual bool isPlaying(); - virtual status_t seekTo(int msec); - virtual status_t getCurrentPosition(int *msec); - virtual status_t getDuration(int *msec); - virtual status_t reset(); - virtual status_t setLooping(int loop); - virtual player_type playerType(); - virtual status_t invoke(const Parcel &request, Parcel *reply); - virtual void setAudioSink(const sp<AudioSink> &audioSink); - virtual status_t setParameter(int key, const Parcel &request); - virtual status_t getParameter(int key, Parcel *reply); - - virtual status_t getMetadata( - const media::Metadata::Filter& ids, Parcel *records); - - virtual status_t dump(int fd, const Vector<String16> &args) const; - - void notifyResetComplete(); - void notifySetSurfaceComplete(); - void notifyDuration(int64_t durationUs); - void notifyPosition(int64_t positionUs); - void notifySeekComplete(); - void notifyListener(int msg, int ext1 = 0, int ext2 = 0, const Parcel *obj=NULL); - void setQCTimedTextListener(const bool val); - -protected: - virtual ~DashPlayerDriver(); - -private: - mutable Mutex mLock; - Condition mCondition; - - // The following are protected through "mLock" - // >>> - bool mResetInProgress; - bool mSetSurfaceInProgress; - int64_t mDurationUs; - int64_t mPositionUs; - // <<< - - sp<ALooper> mLooper; - sp<DashPlayer> mPlayer; - - enum State { - UNINITIALIZED, - STOPPED, - PLAYING, - PAUSED - }; - - State mState; - bool mAtEOS; - - int64_t mStartupSeekTimeUs; - - int mLogLevel; - - DISALLOW_EVIL_CONSTRUCTORS(DashPlayerDriver); -}; - -} // namespace android - - diff --git a/dashplayer/DashPlayerRenderer.cpp b/dashplayer/DashPlayerRenderer.cpp deleted file mode 100644 index 6cd5e46b..00000000 --- a/dashplayer/DashPlayerRenderer.cpp +++ /dev/null @@ -1,798 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -//#define LOG_NDEBUG 0 -#define LOG_TAG "DashPlayerRenderer" - -#include "DashPlayerRenderer.h" -#include <cutils/properties.h> -#include <utils/Log.h> - -#define DPR_MSG_ERROR(...) ALOGE(__VA_ARGS__) -#define DPR_MSG_HIGH(...) if(mLogLevel >= 1){ALOGE(__VA_ARGS__);} -#define DPR_MSG_MEDIUM(...) if(mLogLevel >= 2){ALOGE(__VA_ARGS__);} -#define DPR_MSG_LOW(...) if(mLogLevel >= 3){ALOGE(__VA_ARGS__);} - -namespace android { - -// static -const int64_t DashPlayer::Renderer::kMinPositionUpdateDelayUs = 100000ll; - -DashPlayer::Renderer::Renderer( - const sp<MediaPlayerBase::AudioSink> &sink, - const sp<AMessage> ¬ify) - : mAudioSink(sink), - mNotify(notify), - mNumFramesWritten(0), - mDrainAudioQueuePending(false), - mDrainVideoQueuePending(false), - mAudioQueueGeneration(0), - mVideoQueueGeneration(0), - mAnchorTimeMediaUs(-1), - mAnchorTimeRealUs(-1), - mSeekTimeUs(0), - mFlushingAudio(false), - mFlushingVideo(false), - mHasAudio(false), - mHasVideo(false), - mSyncQueues(false), - mPaused(false), - mWasPaused(false), - mLastPositionUpdateUs(-1ll), - mVideoLateByUs(0ll), - mStats(NULL), - mLogLevel(0) { - - mAVSyncDelayWindowUs = 40000; - - char avSyncDelayMsec[PROPERTY_VALUE_MAX] = {0}; - property_get("persist.dash.avsync.window.msec", avSyncDelayMsec, NULL); - - if(*avSyncDelayMsec) { - int64_t avSyncDelayWindowUs = atoi(avSyncDelayMsec) * 1000; - - if(avSyncDelayWindowUs > 0) { - mAVSyncDelayWindowUs = avSyncDelayWindowUs; - } - } - - DPR_MSG_LOW("AVsync window in Us %lld", mAVSyncDelayWindowUs); - - char property_value[PROPERTY_VALUE_MAX] = {0}; - property_get("persist.dash.debug.level", property_value, NULL); - - if(*property_value) { - mLogLevel = atoi(property_value); - } -} - -DashPlayer::Renderer::~Renderer() { - if(mStats != NULL) { - mStats->logStatistics(); - mStats->logSyncLoss(); - mStats = NULL; - } -} - -void DashPlayer::Renderer::queueBuffer( - bool audio, - const sp<ABuffer> &buffer, - const sp<AMessage> ¬ifyConsumed) { - sp<AMessage> msg = new AMessage(kWhatQueueBuffer, this); - msg->setInt32("audio", static_cast<int32_t>(audio)); - msg->setBuffer("buffer", buffer); - msg->setMessage("notifyConsumed", notifyConsumed); - msg->post(); -} - -void DashPlayer::Renderer::queueEOS(bool audio, status_t finalResult) { - CHECK_NE(finalResult, (status_t)OK); - - if(mSyncQueues) - syncQueuesDone(); - - sp<AMessage> msg = new AMessage(kWhatQueueEOS, this); - msg->setInt32("audio", static_cast<int32_t>(audio)); - msg->setInt32("finalResult", finalResult); - msg->post(); -} - -void DashPlayer::Renderer::flush(bool audio) { - { - Mutex::Autolock autoLock(mFlushLock); - if (audio) { - CHECK(!mFlushingAudio); - mFlushingAudio = true; - } else { - CHECK(!mFlushingVideo); - mFlushingVideo = true; - } - } - - sp<AMessage> msg = new AMessage(kWhatFlush, this); - msg->setInt32("audio", static_cast<int32_t>(audio)); - msg->post(); -} - -void DashPlayer::Renderer::signalTimeDiscontinuity() { - CHECK(mAudioQueue.empty()); - CHECK(mVideoQueue.empty()); - mAnchorTimeMediaUs = -1; - mAnchorTimeRealUs = -1; - mWasPaused = false; - mSeekTimeUs = 0; - mSyncQueues = mHasAudio && mHasVideo; - mIsFirstVideoframeReceived = false; - mPendingPostAudioDrains = false; - mHasAudio = false; - mHasVideo = false; - DPR_MSG_HIGH("signalTimeDiscontinuity mHasAudio %d mHasVideo %d mSyncQueues %d",mHasAudio,mHasVideo,mSyncQueues); -} - -void DashPlayer::Renderer::pause() { - (new AMessage(kWhatPause, this))->post(); -} - -void DashPlayer::Renderer::resume() { - (new AMessage(kWhatResume, this))->post(); -} - -void DashPlayer::Renderer::onMessageReceived(const sp<AMessage> &msg) { - switch (msg->what()) { - case kWhatDrainAudioQueue: - { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mAudioQueueGeneration) { - break; - } - - mDrainAudioQueuePending = false; - - if (onDrainAudioQueue()) { - uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), - (status_t)OK); - - uint32_t numFramesPendingPlayout = - mNumFramesWritten - numFramesPlayed; - - // This is how long the audio sink will have data to - // play back. - int64_t delayUs = - (int64_t)(mAudioSink->msecsPerFrame() - * (float)(numFramesPendingPlayout * 1000ll)); - - // Let's give it more data after about half that time - // has elapsed. - postDrainAudioQueue(delayUs / 2); - } - break; - } - - case kWhatDrainVideoQueue: - { - int32_t generation; - CHECK(msg->findInt32("generation", &generation)); - if (generation != mVideoQueueGeneration) { - break; - } - - mDrainVideoQueuePending = false; - - onDrainVideoQueue(); - - postDrainVideoQueue(); - break; - } - - case kWhatQueueBuffer: - { - onQueueBuffer(msg); - break; - } - - case kWhatQueueEOS: - { - onQueueEOS(msg); - break; - } - - case kWhatFlush: - { - onFlush(msg); - break; - } - - case kWhatAudioSinkChanged: - { - onAudioSinkChanged(); - break; - } - - case kWhatPause: - { - onPause(); - break; - } - - case kWhatResume: - { - onResume(); - break; - } - - default: - TRESPASS(); - break; - } -} - -void DashPlayer::Renderer::postDrainAudioQueue(int64_t delayUs) { - if (mDrainAudioQueuePending || mSyncQueues || mPaused) { - return; - } - - if (mAudioQueue.empty()) { - return; - } - - mDrainAudioQueuePending = true; - sp<AMessage> msg = new AMessage(kWhatDrainAudioQueue, this); - msg->setInt32("generation", mAudioQueueGeneration); - msg->post(delayUs); -} - -void DashPlayer::Renderer::signalAudioSinkChanged() { - (new AMessage(kWhatAudioSinkChanged,this))->post(); -} - -bool DashPlayer::Renderer::onDrainAudioQueue() { - uint32_t numFramesPlayed; - - // Check if first frame is EOS, process EOS and return - if(1 == mAudioQueue.size()) - { - QueueEntry *entry = &*mAudioQueue.begin(); - if (entry->mBuffer == NULL) { - ALOGE("onDrainAudioQueue process EOS"); - notifyEOS(true /* audio */, entry->mFinalResult); - - mAudioQueue.erase(mAudioQueue.begin()); - entry = NULL; - return false; - } - } - - if (mAudioSink->getPosition(&numFramesPlayed) != OK) { - return false; - } - - ssize_t numFramesAvailableToWrite = - mAudioSink->frameCount() - (mNumFramesWritten - numFramesPlayed); - - size_t numBytesAvailableToWrite = - numFramesAvailableToWrite * mAudioSink->frameSize(); - - while (numBytesAvailableToWrite > 0 && !mAudioQueue.empty()) { - QueueEntry *entry = &*mAudioQueue.begin(); - - if (entry->mBuffer == NULL) { - // EOS - - notifyEOS(true /* audio */, entry->mFinalResult); - - mAudioQueue.erase(mAudioQueue.begin()); - entry = NULL; - return false; - } - - if (entry->mOffset == 0) { - int64_t mediaTimeUs; - CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - - DPR_MSG_HIGH("rendering audio at media time %.2f secs", (double)mediaTimeUs / 1E6); - - mAnchorTimeMediaUs = mediaTimeUs; - - uint32_t numFramesPlayed; - CHECK_EQ(mAudioSink->getPosition(&numFramesPlayed), (status_t)OK); - - uint32_t numFramesPendingPlayout = - mNumFramesWritten - numFramesPlayed; - - int64_t realTimeOffsetUs = - (int64_t)(((float)mAudioSink->latency() / 2 - + (float)numFramesPendingPlayout - * mAudioSink->msecsPerFrame()) * 1000ll); - - mAnchorTimeRealUs = - ALooper::GetNowUs() + realTimeOffsetUs; - } - - size_t copy = entry->mBuffer->size() - entry->mOffset; - if (copy > numBytesAvailableToWrite) { - copy = numBytesAvailableToWrite; - } - - CHECK_EQ(mAudioSink->write( - entry->mBuffer->data() + entry->mOffset, copy), - (ssize_t)copy); - - entry->mOffset += copy; - if (entry->mOffset == entry->mBuffer->size()) { - entry->mNotifyConsumed->post(); - mAudioQueue.erase(mAudioQueue.begin()); - - entry = NULL; - } - - numBytesAvailableToWrite -= copy; - size_t copiedFrames = copy / mAudioSink->frameSize(); - mNumFramesWritten += (uint32_t)copiedFrames; - } - - notifyPosition(); - - return !mAudioQueue.empty(); -} - -void DashPlayer::Renderer::postDrainVideoQueue() { - if (mDrainVideoQueuePending || mSyncQueues || mPaused) { - return; - } - - if (mVideoQueue.empty()) { - return; - } - - QueueEntry &entry = *mVideoQueue.begin(); - - sp<AMessage> msg = new AMessage(kWhatDrainVideoQueue, this); - msg->setInt32("generation", mVideoQueueGeneration); - - int64_t delayUs; - - if (entry.mBuffer == NULL) { - // EOS doesn't carry a timestamp. - delayUs = 0; - } else { - int64_t mediaTimeUs; - CHECK(entry.mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - - if (mAnchorTimeMediaUs < 0) { - delayUs = 0; - - if (!mHasAudio) { - mAnchorTimeMediaUs = mediaTimeUs; - mAnchorTimeRealUs = ALooper::GetNowUs(); - } - } else { - if ( (!mHasAudio && mHasVideo) && (mWasPaused == true)) - { - mAnchorTimeMediaUs = mediaTimeUs; - mAnchorTimeRealUs = ALooper::GetNowUs(); - mWasPaused = false; - } - - int64_t realTimeUs = - (mediaTimeUs - mAnchorTimeMediaUs) + mAnchorTimeRealUs; - - delayUs = realTimeUs - ALooper::GetNowUs(); - } - } - - msg->post(delayUs); - - mDrainVideoQueuePending = true; -} - -void DashPlayer::Renderer::onDrainVideoQueue() { - if (mVideoQueue.empty()) { - return; - } - - QueueEntry *entry = &*mVideoQueue.begin(); - - if (entry->mBuffer == NULL) { - // EOS - - notifyPosition(true); - - notifyEOS(false /* audio */, entry->mFinalResult); - - mVideoQueue.erase(mVideoQueue.begin()); - entry = NULL; - - mVideoLateByUs = 0ll; - - return; - } - - int64_t mediaTimeUs; - CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs)); - - int64_t realTimeUs = mediaTimeUs - mAnchorTimeMediaUs + mAnchorTimeRealUs; - int64_t nowUs = ALooper::GetNowUs(); - mVideoLateByUs = nowUs - realTimeUs; - - bool tooLate = (mVideoLateByUs > mAVSyncDelayWindowUs); - - if (tooLate) { - DPR_MSG_HIGH("video late by %lld us (%.2f secs)", - mVideoLateByUs, (double)mVideoLateByUs / 1E6); - if(mStats != NULL) { - mStats->recordLate(realTimeUs,nowUs,mVideoLateByUs,mAnchorTimeRealUs); - } - } else { - DPR_MSG_HIGH("rendering video at media time %.2f secs", (double)mediaTimeUs / 1E6); - if(mStats != NULL) { - mStats->recordOnTime(realTimeUs,nowUs,mVideoLateByUs); - mStats->incrementTotalRenderingFrames(); - mStats->logFps(); - } - } - - entry->mNotifyConsumed->setInt32("render", !tooLate); - entry->mNotifyConsumed->post(); - mVideoQueue.erase(mVideoQueue.begin()); - entry = NULL; - - notifyPosition(); -} - -void DashPlayer::Renderer::notifyEOS(bool audio, status_t finalResult) { - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatEOS); - notify->setInt32("audio", static_cast<int32_t>(audio)); - notify->setInt32("finalResult", finalResult); - notify->post(); -} - -void DashPlayer::Renderer::onQueueBuffer(const sp<AMessage> &msg) { - int32_t audio; - CHECK(msg->findInt32("audio", &audio)); - - if (audio) { - mHasAudio = true; - } else { - mHasVideo = true; - } - - if (dropBufferWhileFlushing(audio, msg)) { - return; - } - - sp<ABuffer> buffer; - CHECK(msg->findBuffer("buffer", &buffer)); - - sp<AMessage> notifyConsumed; - CHECK(msg->findMessage("notifyConsumed", ¬ifyConsumed)); - - QueueEntry entry; - entry.mBuffer = buffer; - entry.mNotifyConsumed = notifyConsumed; - entry.mOffset = 0; - entry.mFinalResult = OK; - - if (audio) { - mAudioQueue.push_back(entry); - int64_t audioTimeUs; - (buffer->meta())->findInt64("timeUs", &audioTimeUs); - if ((mHasVideo && mIsFirstVideoframeReceived) - || !mHasVideo){ - postDrainAudioQueue(); - return; - } - else - { - mPendingPostAudioDrains = true; - DPR_MSG_HIGH("Not rendering Audio Sample with TS: %lld as Video frame is not decoded", audioTimeUs); - } - } else { - mVideoQueue.push_back(entry); - int64_t videoTimeUs; - (buffer->meta())->findInt64("timeUs", &videoTimeUs); - if (!mIsFirstVideoframeReceived) { - mIsFirstVideoframeReceived = true; - DPR_MSG_HIGH("Received first video Sample with TS: %lld", videoTimeUs); - if (mPendingPostAudioDrains) { - mPendingPostAudioDrains = false; - postDrainAudioQueue(); - } - } - postDrainVideoQueue(); - } - - if (!mSyncQueues || mAudioQueue.empty() || mVideoQueue.empty()) { - return; - } - - sp<ABuffer> firstAudioBuffer = (*mAudioQueue.begin()).mBuffer; - sp<ABuffer> firstVideoBuffer = (*mVideoQueue.begin()).mBuffer; - - if (firstAudioBuffer == NULL || firstVideoBuffer == NULL) { - // EOS signalled on either queue. - syncQueuesDone(); - return; - } - - int64_t firstAudioTimeUs; - int64_t firstVideoTimeUs; - CHECK(firstAudioBuffer->meta() - ->findInt64("timeUs", &firstAudioTimeUs)); - CHECK(firstVideoBuffer->meta() - ->findInt64("timeUs", &firstVideoTimeUs)); - - int64_t diff = firstVideoTimeUs - firstAudioTimeUs; - - DPR_MSG_LOW("queueDiff = %.2f secs", (double)diff / 1E6); - - if (diff > 100000ll) { - // Audio data starts More than 0.1 secs before video. - // Drop some audio. - - (*mAudioQueue.begin()).mNotifyConsumed->post(); - mAudioQueue.erase(mAudioQueue.begin()); - return; - } - - syncQueuesDone(); -} - -void DashPlayer::Renderer::syncQueuesDone() { - if (!mSyncQueues) { - return; - } - - mSyncQueues = false; - - if (!mAudioQueue.empty()) { - postDrainAudioQueue(); - } - - if (!mVideoQueue.empty()) { - postDrainVideoQueue(); - } -} - -void DashPlayer::Renderer::onQueueEOS(const sp<AMessage> &msg) { - int32_t audio; - CHECK(msg->findInt32("audio", &audio)); - - if (dropBufferWhileFlushing(audio, msg)) { - return; - } - - int32_t finalResult; - CHECK(msg->findInt32("finalResult", &finalResult)); - - QueueEntry entry; - entry.mOffset = 0; - entry.mFinalResult = finalResult; - - if (audio) { - mAudioQueue.push_back(entry); - postDrainAudioQueue(); - } else { - mVideoQueue.push_back(entry); - postDrainVideoQueue(); - } -} - -void DashPlayer::Renderer::onFlush(const sp<AMessage> &msg) { - int32_t audio; - CHECK(msg->findInt32("audio", &audio)); - - // If we're currently syncing the queues, i.e. dropping audio while - // aligning the first audio/video buffer times and only one of the - // two queues has data, we may starve that queue by not requesting - // more buffers from the decoder. If the other source then encounters - // a discontinuity that leads to flushing, we'll never find the - // corresponding discontinuity on the other queue. - // Therefore we'll stop syncing the queues if at least one of them - // is flushed. - syncQueuesDone(); - - if (audio) { - flushQueue(&mAudioQueue); - - Mutex::Autolock autoLock(mFlushLock); - mFlushingAudio = false; - - mDrainAudioQueuePending = false; - ++mAudioQueueGeneration; - } else { - flushQueue(&mVideoQueue); - - Mutex::Autolock autoLock(mFlushLock); - mFlushingVideo = false; - - mDrainVideoQueuePending = false; - ++mVideoQueueGeneration; - if(mStats != NULL) { - mStats->setVeryFirstFrame(true); - } - } - - notifyFlushComplete(audio); -} - -void DashPlayer::Renderer::flushQueue(List<QueueEntry> *queue) { - while (!queue->empty()) { - QueueEntry *entry = &*queue->begin(); - - if (entry->mBuffer != NULL) { - entry->mNotifyConsumed->post(); - } - - queue->erase(queue->begin()); - entry = NULL; - } -} - -void DashPlayer::Renderer::notifyFlushComplete(bool audio) { - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatFlushComplete); - notify->setInt32("audio", static_cast<int32_t>(audio)); - notify->post(); -} - -bool DashPlayer::Renderer::dropBufferWhileFlushing( - bool audio, const sp<AMessage> &msg) { - bool flushing = false; - - { - Mutex::Autolock autoLock(mFlushLock); - if (audio) { - flushing = mFlushingAudio; - } else { - flushing = mFlushingVideo; - } - } - - if (!flushing) { - return false; - } - - sp<AMessage> notifyConsumed; - if (msg->findMessage("notifyConsumed", ¬ifyConsumed)) { - notifyConsumed->post(); - } - - return true; -} - -void DashPlayer::Renderer::onAudioSinkChanged() { - CHECK(!mDrainAudioQueuePending); - mNumFramesWritten = 0; - uint32_t written; - if (mAudioSink->getFramesWritten(&written) == OK) { - mNumFramesWritten = written; - } -} - -void DashPlayer::Renderer::notifyPosition(bool isEOS) { - if (mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) { - return; - } - - int64_t nowUs = ALooper::GetNowUs(); - - if ((!isEOS) && (mLastPositionUpdateUs >= 0 - && nowUs < mLastPositionUpdateUs + kMinPositionUpdateDelayUs)) { - return; - } - mLastPositionUpdateUs = nowUs; - - int64_t positionUs = (mSeekTimeUs != 0) ? mSeekTimeUs : ((nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs); - - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatPosition); - notify->setInt64("positionUs", positionUs); - notify->setInt64("videoLateByUs", mVideoLateByUs); - notify->post(); -} - -void DashPlayer::Renderer::notifySeekPosition(int64_t seekTime){ - mSeekTimeUs = seekTime; - int64_t nowUs = ALooper::GetNowUs(); - mLastPositionUpdateUs = nowUs; - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("what", kWhatPosition); - notify->setInt64("positionUs", seekTime); - notify->setInt64("videoLateByUs", mVideoLateByUs); - notify->post(); - -} - - -void DashPlayer::Renderer::onPause() { - CHECK(!mPaused); - - mDrainAudioQueuePending = false; - ++mAudioQueueGeneration; - - mDrainVideoQueuePending = false; - ++mVideoQueueGeneration; - - if (mHasAudio) { - mAudioSink->pause(); - } - - DPR_MSG_LOW("now paused audio queue has %d entries, video has %d entries", - mAudioQueue.size(), mVideoQueue.size()); - - mPaused = true; - mWasPaused = true; - - if(mStats != NULL) { - int64_t positionUs; - if(mAnchorTimeRealUs < 0 || mAnchorTimeMediaUs < 0) { - positionUs = -1000; - } else { - int64_t nowUs = ALooper::GetNowUs(); - positionUs = (nowUs - mAnchorTimeRealUs) + mAnchorTimeMediaUs; - } - - mStats->logPause(positionUs); - } -} - -void DashPlayer::Renderer::onResume() { - if (!mPaused) { - return; - } - - if (mHasAudio) { - mAudioSink->start(); - } - - mPaused = false; - - if (!mAudioQueue.empty()) { - postDrainAudioQueue(); - } - - if (!mVideoQueue.empty()) { - postDrainVideoQueue(); - } -} - -void DashPlayer::Renderer::registerStats(sp<DashPlayerStats> stats) { - if(mStats != NULL) { - mStats = NULL; - } - mStats = stats; -} - -status_t DashPlayer::Renderer::setMediaPresence(bool audio, bool bValue) -{ - if (audio) - { - DPR_MSG_LOW("mHasAudio set to %d from %d",bValue,mHasAudio); - mHasAudio = bValue; - } - else - { - DPR_MSG_LOW("mHasVideo set to %d from %d",bValue,mHasVideo); - mHasVideo = bValue; - } - return OK; -} - -} // namespace android - diff --git a/dashplayer/DashPlayerRenderer.h b/dashplayer/DashPlayerRenderer.h deleted file mode 100644 index 89404147..00000000 --- a/dashplayer/DashPlayerRenderer.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DASHPLAYER_RENDERER_H_ - -#define DASHPLAYER_RENDERER_H_ - -#include "DashPlayer.h" - -namespace android { - -struct ABuffer; - -struct DashPlayer::Renderer : public AHandler { - Renderer(const sp<MediaPlayerBase::AudioSink> &sink, - const sp<AMessage> ¬ify); - - void queueBuffer( - bool audio, - const sp<ABuffer> &buffer, - const sp<AMessage> ¬ifyConsumed); - - void queueEOS(bool audio, status_t finalResult); - - void flush(bool audio); - - void signalTimeDiscontinuity(); - - void signalAudioSinkChanged(); - - void pause(); - void resume(); - void notifySeekPosition(int64_t seekTime); - - enum { - kWhatEOS = 'eos ', - kWhatFlushComplete = 'fluC', - kWhatPosition = 'posi', - }; - -protected: - virtual ~Renderer(); - - virtual void onMessageReceived(const sp<AMessage> &msg); - -private: - enum { - kWhatDrainAudioQueue = 'draA', - kWhatDrainVideoQueue = 'draV', - kWhatQueueBuffer = 'queB', - kWhatQueueEOS = 'qEOS', - kWhatFlush = 'flus', - kWhatAudioSinkChanged = 'auSC', - kWhatPause = 'paus', - kWhatResume = 'resm', - }; - - struct QueueEntry { - sp<ABuffer> mBuffer; - sp<AMessage> mNotifyConsumed; - size_t mOffset; - status_t mFinalResult; - }; - - static const int64_t kMinPositionUpdateDelayUs; - - sp<MediaPlayerBase::AudioSink> mAudioSink; - sp<AMessage> mNotify; - List<QueueEntry> mAudioQueue; - List<QueueEntry> mVideoQueue; - uint32_t mNumFramesWritten; - - bool mDrainAudioQueuePending; - bool mDrainVideoQueuePending; - int32_t mAudioQueueGeneration; - int32_t mVideoQueueGeneration; - - int64_t mAnchorTimeMediaUs; - int64_t mAnchorTimeRealUs; - int64_t mSeekTimeUs; - - Mutex mFlushLock; // protects the following 2 member vars. - bool mFlushingAudio; - bool mFlushingVideo; - - bool mHasAudio; - bool mHasVideo; - bool mSyncQueues; - - bool mIsFirstVideoframeReceived; - bool mPendingPostAudioDrains; - - bool mPaused; - bool mWasPaused; // if paused then store the info - - int64_t mLastPositionUpdateUs; - int64_t mVideoLateByUs; - int64_t mAVSyncDelayWindowUs; - - bool onDrainAudioQueue(); - void postDrainAudioQueue(int64_t delayUs = 0); - - void onDrainVideoQueue(); - void postDrainVideoQueue(); - - void onQueueBuffer(const sp<AMessage> &msg); - - void onQueueEOS(const sp<AMessage> &msg); - void onFlush(const sp<AMessage> &msg); - void onAudioSinkChanged(); - void onPause(); - void onResume(); - - void notifyEOS(bool audio, status_t finalResult); - void notifyFlushComplete(bool audio); - void notifyPosition(bool isEOS = false); - void notifyVideoLateBy(int64_t lateByUs); - - void flushQueue(List<QueueEntry> *queue); - bool dropBufferWhileFlushing(bool audio, const sp<AMessage> &msg); - void syncQueuesDone(); - - // for qualcomm statistics profiling - public: - - void registerStats(sp<DashPlayerStats> stats); - status_t setMediaPresence(bool audio, bool bValue); - - private: - sp<DashPlayerStats> mStats; - int mLogLevel; - - DISALLOW_EVIL_CONSTRUCTORS(Renderer); -}; - -} // namespace android - -#endif // DASHPLAYER_RENDERER_H_ diff --git a/dashplayer/DashPlayerSource.h b/dashplayer/DashPlayerSource.h deleted file mode 100644 index 3246aa96..00000000 --- a/dashplayer/DashPlayerSource.h +++ /dev/null @@ -1,123 +0,0 @@ -/* - * Copyright (C) 2010 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef DASHPLAYER_SOURCE_H_ - -#define DASHPLAYER_SOURCE_H_ - -#include "DashPlayer.h" - -namespace android { - -struct ABuffer; - -struct DashPlayer::Source : public RefBase { - Source() {} - - virtual void start() = 0; - virtual void stop() {} - - // Returns OK iff more data was available, - // an error or ERROR_END_OF_STREAM if not. - virtual status_t feedMoreTSData() = 0; - - virtual sp<MetaData> getFormat(int audio) = 0; - - virtual status_t dequeueAccessUnit( - int track, sp<ABuffer> *accessUnit) = 0; - - virtual status_t getDuration(int64_t * /*durationUs*/) { - return INVALID_OPERATION; - } - - virtual status_t seekTo(int64_t /*seekTimeUs*/) { - return INVALID_OPERATION; - } - - virtual bool isSeekable() { - return false; - } - - virtual status_t getNewSeekTime(int64_t* /*newSeek*/) { - return INVALID_OPERATION; - } - - virtual status_t prepareAsync() { - return INVALID_OPERATION; - } - - virtual status_t isPrepareDone() { - return INVALID_OPERATION; - } - - virtual status_t getParameter(int /*key*/, void ** /*data*/, size_t * /*size*/) { - return INVALID_OPERATION; - } - - virtual status_t setParameter(int /*key*/, void * /*data*/, size_t /*size*/) { - return INVALID_OPERATION; - } - virtual void notifyRenderingPosition(int64_t /*nRenderingTS*/){} - - virtual status_t setupSourceData(const sp<AMessage> & /*msg*/, int /*iTrack*/){ - return INVALID_OPERATION; - } - virtual status_t postNextTextSample(sp<ABuffer> /*accessUnit*/,const sp<AMessage> &/*msg*/,int /*iTrack*/) { - return INVALID_OPERATION; - } - - virtual status_t getMediaPresence(bool &/*audio*/, bool &/*video*/, bool &/*text*/) { - return INVALID_OPERATION; - } - - virtual status_t pause() { - ALOGE("Pause called on Wrong DataSource.. Please check !!!"); - return INVALID_OPERATION; - } - - virtual status_t resume() { - ALOGE("Resume called on Wrong DataSource.. Please check !!!"); - return INVALID_OPERATION; - } - - virtual status_t getRepositionRange(uint64_t* /*pMin*/, uint64_t* /*pMax*/, uint64_t* /*pMaxDepth*/) { - return INVALID_OPERATION; - } - - virtual sp<AMessage> getTrackInfo(size_t /*index*/) { - return NULL; - } - - virtual status_t getTrackCount() - { - return INVALID_OPERATION; - } - - virtual bool isPlaybackDiscontinued() { - return false; - } - -protected: - virtual ~Source() {} - -private: - DISALLOW_EVIL_CONSTRUCTORS(Source); -}; - -} // namespace android - -#endif // DASHPLAYER_SOURCE_H_ - diff --git a/dashplayer/DashPlayerStats.cpp b/dashplayer/DashPlayerStats.cpp deleted file mode 100644 index bab014e0..00000000 --- a/dashplayer/DashPlayerStats.cpp +++ /dev/null @@ -1,290 +0,0 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "DashPlayerStats.h" - -#define NO_MIMETYPE_AVAILABLE "N/A" - -namespace android { - -DashPlayerStats::DashPlayerStats() { - Mutex::Autolock autoLock(mStatsLock); - mMIME = new char[strlen(NO_MIMETYPE_AVAILABLE)+1]; - strlcpy(mMIME,NO_MIMETYPE_AVAILABLE, strlen(NO_MIMETYPE_AVAILABLE)+1); - mNumVideoFramesDecoded = 0; - mNumVideoFramesDropped = 0; - mConsecutiveFramesDropped = 0; - mCatchupTimeStart = 0; - mNumTimesSyncLoss = 0; - mMaxEarlyDelta = 0; - mMaxLateDelta = 0; - mMaxTimeSyncLoss = 0; - mTotalFrames = 0; - mFirstFrameLatencyStartUs = getTimeOfDayUs(); - mLastFrame = 0; - mLastFrameUs = 0; - mStatisticsFrames = 0; - mFPSSumUs = 0; - mVeryFirstFrame = true; - mSeekPerformed = false; - mTotalTime = 0; - mFirstFrameTime = 0; - mTotalRenderingFrames = 0; - mBufferingEvent = false; - mFd = -1; - mFileOut = NULL; -} - -DashPlayerStats::~DashPlayerStats() { - Mutex::Autolock autoLock(mStatsLock); - if(mFileOut){ - fclose(mFileOut); - mFileOut = NULL; - } - if(mMIME) { - delete[] mMIME; - mMIME = NULL; - } -} - -void DashPlayerStats::setFileDescAndOutputStream(int fd) { - Mutex::Autolock autoLock(mStatsLock); - mFd = fd; - if(mFileOut){ - fclose(mFileOut); - mFileOut = NULL; - } - mFileOut = fdopen(dup(fd), "w"); -} - -void DashPlayerStats::setMime(const char* mime) { - Mutex::Autolock autoLock(mStatsLock); - if(mime != NULL) { - int mimeLen = (int)strlen(mime); - if(mMIME) { - delete[] mMIME; - mMIME = NULL; - } - - mMIME = new char[mimeLen+1]; - strlcpy(mMIME,mime,mimeLen+1); - } -} - -void DashPlayerStats::setVeryFirstFrame(bool /*vff*/) { - Mutex::Autolock autoLock(mStatsLock); - mVeryFirstFrame = true; -} - -void DashPlayerStats::notifySeek() { - Mutex::Autolock autoLock(mStatsLock); - mFirstFrameLatencyStartUs = getTimeOfDayUs(); - mSeekPerformed = true; -} - -void DashPlayerStats::notifyBufferingEvent() { - Mutex::Autolock autoLock(mStatsLock); - mBufferingEvent = true; -} - -void DashPlayerStats::incrementTotalFrames() { - Mutex::Autolock autoLock(mStatsLock); - mTotalFrames++; -} - -void DashPlayerStats::incrementTotalRenderingFrames() { - Mutex::Autolock autoLock(mStatsLock); - mTotalRenderingFrames++; -} - -void DashPlayerStats::incrementDroppedFrames() { - Mutex::Autolock autoLock(mStatsLock); - mNumVideoFramesDropped++; -} - -void DashPlayerStats::logStatistics() { - if(mFileOut) { - Mutex::Autolock autoLock(mStatsLock); - fprintf(mFileOut, "=====================================================\n"); - fprintf(mFileOut, "Mime Type: %s\n",mMIME); - fprintf(mFileOut, "Number of total frames: %llu\n",(unsigned long long)mTotalFrames); - fprintf(mFileOut, "Number of frames dropped: %lld\n",(signed long long)mNumVideoFramesDropped); - fprintf(mFileOut, "Number of frames rendered: %llu\n",(unsigned long long)mTotalRenderingFrames); - fprintf(mFileOut, "Percentage dropped: %.2f\n", - mTotalFrames == 0 ? 0.0 : (double)mNumVideoFramesDropped / (double)mTotalFrames); - fprintf(mFileOut, "=====================================================\n"); - } -} - -void DashPlayerStats::logPause(int64_t positionUs) { - if(mFileOut) { - fprintf(mFileOut, "=====================================================\n"); - fprintf(mFileOut, "Pause position: %lld ms\n",(signed long long)positionUs/1000); - fprintf(mFileOut, "=====================================================\n"); - } -} - -void DashPlayerStats::logSeek(int64_t seekTimeUs) { - if(mFileOut) { - Mutex::Autolock autoLock(mStatsLock); - fprintf(mFileOut, "=====================================================\n"); - fprintf(mFileOut, "Seek position: %lld ms\n",(signed long long)seekTimeUs/1000); - fprintf(mFileOut, "Seek latency: %lld ms\n",(signed long long)(getTimeOfDayUs() - mFirstFrameLatencyStartUs)/1000); - fprintf(mFileOut, "=====================================================\n"); - } -} - -void DashPlayerStats::recordLate(int64_t ts, int64_t clock, int64_t delta, int64_t anchorTime) { - Mutex::Autolock autoLock(mStatsLock); - mNumVideoFramesDropped++; - mConsecutiveFramesDropped++; - if (mConsecutiveFramesDropped == 1){ - mCatchupTimeStart = (uint32_t)anchorTime; - } - - logLate(ts,clock,delta); -} - -void DashPlayerStats::recordOnTime(int64_t ts, int64_t clock, int64_t delta) { - Mutex::Autolock autoLock(mStatsLock); - mNumVideoFramesDecoded++; - mConsecutiveFramesDropped = 0; - logOnTime(ts,clock,delta); -} - -void DashPlayerStats::logSyncLoss() { - if(mFileOut) { - Mutex::Autolock autoLock(mStatsLock); - fprintf(mFileOut, "=====================================================\n"); - fprintf(mFileOut, "Number of times AV Sync Losses = %u\n", mNumTimesSyncLoss); - fprintf(mFileOut, "Max Video Ahead time delta = %lld\n", (signed long long)-mMaxEarlyDelta/1000); - fprintf(mFileOut, "Max Video Behind time delta = %lld\n", (signed long long)mMaxLateDelta/1000); - fprintf(mFileOut, "Max Time sync loss = %lld\n",(signed long long)mMaxTimeSyncLoss/1000); - fprintf(mFileOut, "=====================================================\n"); - } -} - -void DashPlayerStats::logFps() { - if (mFileOut) { - Mutex::Autolock autoLock(mStatsLock); - int64_t now = getTimeOfDayUs(); - - if(mTotalRenderingFrames < 2){ - mLastFrameUs = now; - mFirstFrameTime = now; - } - - mTotalTime = now - mFirstFrameTime; - int64_t diff = now - mLastFrameUs; - if (diff > 250000 && !mVeryFirstFrame && !mBufferingEvent) { - double fps =((double)(mTotalRenderingFrames - mLastFrame) * 1E6)/(double)diff; - if (mStatisticsFrames == 0) { - fps =((double)(mTotalRenderingFrames - mLastFrame - 1) * 1E6)/(double)diff; - } - fprintf(mFileOut, "Frames per second: %.4f, Duration of measurement: %lld\n", fps,(signed long long)diff); - mFPSSumUs += fps; - ++mStatisticsFrames; - mLastFrameUs = now; - mLastFrame = mTotalRenderingFrames; - } - - if(mSeekPerformed) { - mVeryFirstFrame = false; - mSeekPerformed = false; - } else if(mVeryFirstFrame) { - logFirstFrame(); - fprintf(mFileOut, "setting first frame time\n"); - mLastFrameUs = now; - } else if(mBufferingEvent) { - mLastFrameUs = now; - mLastFrame = mTotalRenderingFrames; - } - mBufferingEvent = false; - } -} - -void DashPlayerStats::logFpsSummary() { - if (mFileOut) { - logStatistics(); - logSyncLoss(); - { - Mutex::Autolock autoLock(mStatsLock); - fprintf(mFileOut, "=========================================================\n"); - fprintf(mFileOut, "Average Frames Per Second: %.4f\n", mFPSSumUs/((double)mStatisticsFrames)); - fprintf(mFileOut, "Total Frames (rendered) / Total Time: %.4f\n", ((double)(mTotalRenderingFrames-1)*1E6)/((double)mTotalTime)); - fprintf(mFileOut, "========================================================\n"); - } - } -} - -int64_t DashPlayerStats::getTimeOfDayUs() { - struct timeval tv; - gettimeofday(&tv, NULL); - return (int64_t)tv.tv_sec * 1000000 + tv.tv_usec; -} - -// WARNING: Most private functions are only thread-safe within mStatsLock -inline void DashPlayerStats::logFirstFrame() { - fprintf(mFileOut, "=====================================================\n"); - fprintf(mFileOut, "First frame latency: %lld ms\n",(signed long long)(getTimeOfDayUs()-mFirstFrameLatencyStartUs)/1000); - fprintf(mFileOut, "=====================================================\n"); - mVeryFirstFrame = false; -} - -inline void DashPlayerStats::logCatchUp(int64_t ts, int64_t clock, int64_t /*delta*/) { - if (mConsecutiveFramesDropped > 0) { - mNumTimesSyncLoss++; - if (mMaxTimeSyncLoss < (clock - mCatchupTimeStart) && clock > 0 && ts > 0) { - mMaxTimeSyncLoss = clock - mCatchupTimeStart; - } - } -} - -inline void DashPlayerStats::logLate(int64_t ts, int64_t clock, int64_t delta) { - if (mMaxLateDelta < delta && clock > 0 && ts > 0) { - mMaxLateDelta = delta; - } -} - -inline void DashPlayerStats::logOnTime(int64_t ts, int64_t clock, int64_t delta) { - bool needLogLate = false; - logCatchUp(ts, clock, delta); - if (delta <= 0) { - if ((-delta) > (-mMaxEarlyDelta) && clock > 0 && ts > 0) { - mMaxEarlyDelta = delta; - } - } - else { - needLogLate = true; - } - - if(needLogLate) logLate(ts, clock, delta); -} - -} // namespace android diff --git a/dashplayer/DashPlayerStats.h b/dashplayer/DashPlayerStats.h deleted file mode 100644 index 198cb05e..00000000 --- a/dashplayer/DashPlayerStats.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (c) 2013, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef DASHPLAYER_STATS_H_ - -#define DASHPLAYER_STATS_H_ - -#include <utils/RefBase.h> -#include <utils/threads.h> -#include <utils/Log.h> - -namespace android { - -class DashPlayerStats : public RefBase { - public: - DashPlayerStats(); - ~DashPlayerStats(); - - void setMime(const char* mime); - void setVeryFirstFrame(bool vff); - void notifySeek(); - void incrementTotalFrames(); - void incrementDroppedFrames(); - void logStatistics(); - void logPause(int64_t positionUs); - void logSeek(int64_t seekTimeUs); - void recordLate(int64_t ts, int64_t clock, int64_t delta, int64_t anchorTime); - void recordOnTime(int64_t ts, int64_t clock, int64_t delta); - void logSyncLoss(); - void logFps(); - void logFpsSummary(); - static int64_t getTimeOfDayUs(); - void incrementTotalRenderingFrames(); - void notifyBufferingEvent(); - void setFileDescAndOutputStream(int fd); - - private: - void logFirstFrame(); - void logCatchUp(int64_t ts, int64_t clock, int64_t delta); - void logLate(int64_t ts, int64_t clock, int64_t delta); - void logOnTime(int64_t ts, int64_t clock, int64_t delta); - - mutable Mutex mStatsLock; - bool mStatistics; - char* mMIME; - int64_t mNumVideoFramesDecoded; - int64_t mNumVideoFramesDropped; - int64_t mConsecutiveFramesDropped; - int64_t mCatchupTimeStart; - uint32_t mNumTimesSyncLoss; - int64_t mMaxEarlyDelta; - int64_t mMaxLateDelta; - int64_t mMaxTimeSyncLoss; - uint64_t mTotalFrames; - int64_t mFirstFrameLatencyStartUs; - int64_t mLastFrame; - int64_t mLastFrameUs; - double mFPSSumUs; - int64_t mStatisticsFrames; - bool mVeryFirstFrame; - bool mSeekPerformed; - int64_t mTotalTime; - int64_t mFirstFrameTime; - uint64_t mTotalRenderingFrames; - bool mBufferingEvent; - int mFd; - FILE *mFileOut; -}; - -} // namespace android - -#endif // DASHPLAYER_STATS_H_ diff --git a/dashplayer/jni/Android.mk b/dashplayer/jni/Android.mk deleted file mode 100644 index 0e127c49..00000000 --- a/dashplayer/jni/Android.mk +++ /dev/null @@ -1,26 +0,0 @@ -LOCAL_PATH:= $(call my-dir) -include $(CLEAR_VARS) - -LOCAL_SRC_FILES:= \ - android_media_ExtMediaPlayer.cpp \ - -LOCAL_SHARED_LIBRARIES := \ - libandroid_runtime \ - libnativehelper \ - libutils \ - libbinder \ - liblog \ - libstagefright \ - libstagefright_foundation \ - libdl \ - -LOCAL_C_INCLUDES += \ - $(TOP)/frameworks/base/core/jni \ - $(TOP)/frameworks/av/media/libstagefright \ - $(LOCAL_PATH)/../../QCMediaPlayer/native \ - -LOCAL_MODULE:= libextmedia_jni - -include $(BUILD_SHARED_LIBRARY) - -include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/dashplayer/jni/android_media_ExtMediaPlayer.cpp b/dashplayer/jni/android_media_ExtMediaPlayer.cpp deleted file mode 100755 index 764e02c9..00000000 --- a/dashplayer/jni/android_media_ExtMediaPlayer.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/*Copyright (c) 2013, 2015, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#define LOG_TAG "ExtMediaPlayer-JNI" - -#include "android_media_ExtMediaPlayer.h" -#include <dlfcn.h> - -using namespace android; - - -extern "C" MediaPlayerListener* -CreateJNIExtMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz,const sp<MediaPlayerListener>& listener) { - return (new JNIExtMediaPlayerListener(env, thiz, weak_thiz, listener)); -} - -extern "C" bool -checkExtMedia(JNIEnv *env, jobject thiz){ - jclass clazz = NULL; - bool nRet = false; - clazz = env->FindClass("com/qualcomm/qcmedia/QCMediaPlayer"); - if (clazz != NULL) { - if (env->IsInstanceOf(thiz,clazz)) { - nRet = true; - ALOGD("QCMediaPlayer mediaplayer present"); - } else { - ALOGE("env->IsInstanceOf fails"); - } - } else { - //Clear the exception as QCMediaPlayer is optional - env->ExceptionClear(); - ALOGE("QCMediaPlayer could not be located...."); - } - return nRet; -} - -JNIExtMediaPlayerListener::JNIExtMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz,const sp<MediaPlayerListener>& listener) { - jclass clazz = env->GetObjectClass(thiz); - if (clazz == NULL) { - ALOGE("Can't find android/media/MediaPlayer"); - jniThrowException(env, "java/lang/Exception", NULL); - return; - } - mpListener = listener; - extfields.ext_post_event = env->GetStaticMethodID(clazz, "QCMediaPlayerNativeEventHandler", - "(Ljava/lang/Object;IIILjava/lang/Object;)V"); - mClass = (jclass)env->NewGlobalRef(clazz); - - // We use a weak reference so the MediaPlayer object can be garbage collected. - // The reference is only used as a proxy for callbacks. - mObject = env->NewGlobalRef(weak_thiz); -} - -JNIExtMediaPlayerListener::~JNIExtMediaPlayerListener() { - // remove global references - JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->DeleteGlobalRef(mObject); - env->DeleteGlobalRef(mClass); -} - - -void JNIExtMediaPlayerListener::notify(int msg, int ext1, int ext2, const Parcel *obj) { - JNIEnv *env = AndroidRuntime::getJNIEnv(); - if (env && obj && obj->dataSize() > 0) { - jobject jParcel = createJavaParcelObject(env); - if (jParcel != NULL) { - if((extfields.ext_post_event != NULL) && - ((msg == MEDIA_PREPARED) || (msg == MEDIA_TIMED_TEXT) || (msg == MEDIA_QOE))) { - ALOGE("JNIExtMediaPlayerListener::notify calling ext_post_event"); - Parcel* nativeParcel = parcelForJavaObject(env, jParcel); - if(nativeParcel != NULL) { - nativeParcel->setData(obj->data(), obj->dataSize()); - env->CallStaticVoidMethod(mClass, extfields.ext_post_event, mObject, - msg, ext1, ext2, jParcel); - env->DeleteLocalRef(jParcel); - ALOGD("JNIExtMediaPlayerListener::notify ext_post_event done"); - } - } else { - ALOGD("JNIExtMediaPlayerListener::notify calling for generic event"); - mpListener->notify(msg, ext1, ext2, obj); - } - } - } else { - if((extfields.ext_post_event != NULL) && - ((msg == MEDIA_PREPARED) || (msg == MEDIA_TIMED_TEXT) ||(msg == MEDIA_QOE))) - { - ALOGD("JNIExtMediaPlayerListener::notify calling ext_post_events"); - env->CallStaticVoidMethod(mClass, extfields.ext_post_event, mObject, msg, ext1, ext2, NULL); - } else { - ALOGD("JNIExtMediaPlayerListener::notify for generic events"); - mpListener->notify(msg, ext1, ext2, obj); - } - } - return; -} - - -extern "C" MediaPlayer *CreateNativeQCMediaPlayer() -{ - const char* QCMEDIAPLAYER_LIB = "libqcmediaplayer.so"; - const char* QCMEDIAPLAYER_CREATE_FN = "CreateQCMediaPlayer"; - void* pQCMediaPlayerLib = NULL; - - typedef MediaPlayer* (*CreateQCMediaPlayerFn)(); - - /* Open library */ - ALOGI("calling dlopen on QCMEDIAPLAYER_LIB"); - pQCMediaPlayerLib = ::dlopen(QCMEDIAPLAYER_LIB, RTLD_LAZY); - - if (pQCMediaPlayerLib == NULL) { - ALOGE("Failed to open QCMEDIAPLAYER_LIB Error : %s ",::dlerror()); - return NULL; - } - - CreateQCMediaPlayerFn pCreateFnPtr = NULL; - ALOGI("calling dlsym on pQCMediaPlayerLib for QCMEDIAPLAYER_CREATE_FN "); - pCreateFnPtr = (CreateQCMediaPlayerFn) dlsym(pQCMediaPlayerLib, QCMEDIAPLAYER_CREATE_FN); - - if (pCreateFnPtr == NULL) { - ALOGE("Could not locate CreateQCMediaPlayerFn pCreateFnPtr"); - return NULL; - } - - MediaPlayer* pQCMediaPlayer = pCreateFnPtr(); - - if(pQCMediaPlayer==NULL) { - ALOGE("Failed to invoke CreateQCMediaPlayerFn..."); - return NULL; - } - - return pQCMediaPlayer; -} - diff --git a/dashplayer/jni/android_media_ExtMediaPlayer.h b/dashplayer/jni/android_media_ExtMediaPlayer.h deleted file mode 100644 index b5cc3001..00000000 --- a/dashplayer/jni/android_media_ExtMediaPlayer.h +++ /dev/null @@ -1,60 +0,0 @@ -/*Copyright (c) 2013, 2015, The Linux Foundation. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are - * met: - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * * Redistributions in binary form must reproduce the above - * copyright notice, this list of conditions and the following - * disclaimer in the documentation and/or other materials provided - * with the distribution. - * * Neither the name of The Linux Foundation nor the names of its - * contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE - * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN - * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#ifndef _ANDROID_MEDIA_EXTMEDIAPLAYER_H_ -#define _ANDROID_MEDIA_EXTMEDIAPLAYER_H_ - -//#define LOG_NDEBUG 0 -#include <qcmediaplayer.h> -#include "JNIHelp.h" -#include "android_runtime/AndroidRuntime.h" -#include "android_runtime/Log.h" -#include "android_os_Parcel.h" -#include <binder/Parcel.h> - -using namespace android; - -struct extfields_t { - jmethodID ext_post_event; -}; -static extfields_t extfields; - -class JNIExtMediaPlayerListener: public MediaPlayerListener { - public: - JNIExtMediaPlayerListener(JNIEnv* env, jobject thiz, jobject weak_thiz, const sp<MediaPlayerListener>& listener); - ~JNIExtMediaPlayerListener(); - virtual void notify(int msg, int ext1, int ext2, const Parcel *obj = NULL); - private: - JNIExtMediaPlayerListener(); - JNIExtMediaPlayerListener( const JNIExtMediaPlayerListener &); - JNIExtMediaPlayerListener& operator=(const JNIExtMediaPlayerListener&); - jclass mClass; // Reference to MediaPlayer class - jobject mObject; // Weak ref to MediaPlayer Java object to call on - sp<MediaPlayerListener> mpListener; -}; -#endif //_ANDROID_MEDIA_EXTMEDIAPLAYER_H_ |