ДэниелЖивой SDKс2015выпущен в годуRTSP、RTMPМодуль прямой трансляции,Итерация никогда не останавливается,SmartPlayer обладает мощными функциями, высокой производительностью, высокой стабильностью, сверхнизкой задержкой и сверхнизким использованием ресурсов. Нет необходимости уточнять,Полностью самостоятельно разработанное ядро,Кроссплатформенная прямая трансляция RTSP и RTMP, единогласно признанная в отрасли. В этой статье в качестве примера рассматривается платформа Android.,Представьте, как Вниз интегрирует модули воспроизведения RTSP и RTMP.
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" >
</uses-permission>
<uses-permission android:name="android.permission.INTERNET" >
</uses-permission>
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
static {
System.loadLibrary("SmartPlayer");
}
splits {
abi {
enable true
reset()
// Specifies a list of ABIs that Gradle should create APKs for
include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' //select ABIs to build APKs for
// Specify that we do not want to also generate a universal APK that includes all ABIs
universalApk true
}
}
<string name="app_name">SmartPlayerSDKDemo</string>
Подробное объяснение интерфейса SDK плеера Android RTSP | RTMP. | |||
---|---|---|---|
описание звонка | интерфейс | интерфейсописывать | |
Вызывается первым, в случае успеха будет возвращен экземпляр воспроизведения. | SmartPlayerOpen | Инициализировать проигрыватель, установить контекстную информацию, вернуть дескриптор проигрывателя | |
Обратный вызов события | SetSmartPlayerEventCallbackV2 | Установить обратный вызов события | |
Настройки жесткого декодирования (H.264) | SetSmartPlayerVideoHWDecoder | Установите, использовать ли жесткое декодирование H.264 для воспроизведения. Если жесткое декодирование не поддерживается, оно автоматически адаптируется к мягкому декодированию. | |
Настройки жесткого декодирования (H.265) | SetSmartPlayerVideoHevcHWDecoder | Установите, использовать ли жесткое декодирование H.265 для воспроизведения. Если жесткое декодирование не поддерживается, оно автоматически адаптируется к мягкому декодированию. | |
видеоэкран Режим заполнения | SmartPlayerSetRenderScaleMode | Установите режим заполнения видеоэкрана, например, заполнение всего изображения или пропорциональное заполнение изображения. Если этот параметр не установлен, по умолчанию будет заполнено все изображение. | |
Установить тип рендеринга в режиме SurfaceView | SmartPlayerSetSurfaceRenderFormat | Установите тип рендеринга в режиме SurfaceView (когда второй параметр NTRenderer.CreateRenderer передает значение false) 0: формат RGB565, если не установлен, этот режим используется по умолчанию 1: формат ARGB8888; | |
Установите эффект сглаживания в режиме SurfaceView. | SmartPlayerSetSurfaceAntiAlias | Установите эффект сглаживания в режиме SurfaceView (если второй параметр NTRenderer.CreateRenderer имеет значение false. Примечание. После включения режима сглаживания производительность изображения может снизиться, используйте с осторожностью). | |
Установите поверхность воспроизведения | SmartPlayerSetSurface | Установите поверхность воспроизведения,если ноль,затем воспроизведи чистый звук | |
Установите режим самостоятельного рисования Mediacodec при жестком декодировании видео. | SmartPlayerSetHWRenderMode | В этом режиме совместимость и эффективность аппаратного декодирования лучше, а функции обратного вызова YUV/RGB, моментального снимка и масштабирования изображения будут недоступны. | |
Обновить поверхность жесткого декодирования | SmartPlayerUpdateHWRenderSurface | настраивать Обновить поверхность жесткого декодирования | |
Аудио обратный вызов | YUV/RGB | SmartPlayerSetExternalRender | Обеспечить декодированный интерфейс данных YUV/RGB,Для пользователей для рендеринга или дальнейшей обработки (например, анализа видео) |
Audio | SmartPlayerSetExternalAudioOutput | Обратный вызов аудиоданных на верхний уровень (для вторичной обработки) | |
тип аудиовыхода | SmartPlayerSetAudioOutputType | Если для параметра use_audiotrack установлено значение 0, устройство вывода будет выбрано автоматически. Если для него установлено значение 1, будет использоваться режим аудиодорожки. В режиме эхоподавления «один к одному» выберите режим аудиодорожки. | |
Тип видеовыхода | NTRenderer.CreateRenderer (в верхней демо) | Второй параметр, если он равен true, использует openGLES для рисования, если false, используется SurfaceView по умолчанию. | |
режим воспроизведения | Настройка времени буфера | SmartPlayerSetBuffer | Установите буфер данных кэша завершения воспроизведения, единица измерения: миллисекунды. Если буфер не требуется, установите его на 0. |
Открыть мгновенно на первом экране | SmartPlayerSetFastStartup | После настройки быстрого запуска,Если CDN кэширует GOP,выполнить Открыть мгновенно на первом экране | |
режим с низкой задержкой | SmartPlayerSetLowLatencyMode | Для ожиданий, аналогичных кукольным машинам в прямом эфире и т. д.сверхнизкая задержкасценарии использования,сверхнизкая задержкарежим воспроизведения Вниз,Задержка может достигать 200~400 мс. | |
Быстрое переключение URL-адресов | SmartPlayerSwitchPlaybackUrl | Быстрое переключение URL-адреса воспроизведения. При быстром переключении изменяется только часть источника воспроизведения. Он подходит для быстрого переключения между различными потоками данных (например, переключения между двумя камерами кукольной машины или переключения между потоками высокого и низкого разрешения). | |
Настройки режима RTSP TCP/UDP | SmartPlayerSetRTSPTcpMode | Установить режим RTSP TCP/UDP. Если этот параметр не установлен, будет использоваться режим UDP по умолчанию. | |
Настройка тайм-аута RTSP | SmartPlayerSetRTSPTimeout | Установите тайм-аут RTSP, единица измерения — секунды, должно быть больше 0. | |
Установите автоматическое переключение RTSP TCP/UDP | SmartPlayerSetRTSPAutoSwitchTcpUdp | Что касается RTSP, некоторые из них могут поддерживать rtp через udp, а некоторые могут поддерживать rtp через TCP. Для удобства использования в некоторых сценариях можно включить переключатель автоматической попытки. Если после включения udp невозможно воспроизвести, SDK автоматически попытается использовать TCP. Если tcp не может быть воспроизведен, SDK автоматически попытается использовать udp. | |
Установите имя пользователя и пароль RTSP | SetRTSPAuthenticationInfo | Если РТСП URL-адрес уже содержит имя пользователя и пароль, Имя пользователя и пароль, установленные для этого интерфейса, будут недействительны. То есть вам необходимо использовать имя пользователя и пароль, установленные этим интерфейсом, для аутентификации. RTSP URL-адрес не может содержать имя пользователя и пароль. | |
Отключение звука в реальном времени | SmartPlayerSetMute | Отключение звука в реальном времени | |
Установить громкость воспроизведения | SmartPlayerSetAudioVolume | Громкость окончания воспроизведения регулируется в реальном времени, диапазон: [0,100], 0 — звук без звука, 100 — максимальная громкость исходных потоковых данных. | |
Установите, отключать ли расширенный RTMP | DisableEnhancedRTMP | отключить расширенный RTMP, SDK по умолчанию включает расширенный RTMP | |
Скриншот в реальном времени | CaptureImage | Поддерживает форматы JPEG и PNG. | |
Видео поворот зеркала | вращать | SmartPlayerSetRotation | настраиватьпо часовой стрелкевращать, Обратите внимание, что помимо 0 градусов, Другие углы потребуют дополнительной производительности и в настоящее время поддерживаются. 0 градусов, 90 градусов, 180 градусов, 270 градусов вращать |
горизонтальный разворот | SmartPlayerSetFlipHorizontal | настраиватьвидеогоризонтальный разворот | |
вертикальная инверсия | SmartPlayerSetFlipVertical | настраиватьвидеовертикальная инверсия | |
Установить URL | SmartPlayerSetUrl | Установите URL-адрес RTMP/RTSP, который необходимо воспроизвести или записать. | |
Начать играть | SmartPlayerStartPlay | Начать игратьRTSP/RTMPпоток | |
Хватит играть | SmartPlayerStopPlay | Хватит игратьRTSP/RTMPпоток | |
Закрыть экземпляр воспроизведения | SmartPlayerClose | В конце необходимо вызвать closeinterface для освобождения ресурсов. |
В этой статье используется Daniu Live SDK. Платформа Android SmartPlayerV2 является примером. Перед воспроизведением установите конфигурацию параметров инициализации (мягкое декодирование или жесткое декодирование, буфер). время и т. д.) и RTSP или RTMP, который необходимо воспроизвести. URL,точка Начать играть Вот и все。
При onCreate() сначала создается новый SmartPlayerJniV2():
/*
* SmartPlayer.java
* Author: daniusdk.com
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_smart_player);
...
libPlayer = new SmartPlayerJniV2();
myContext = this.getApplicationContext();
}
Начать играть、Хватит игратьвыполнить,Начать игратькогда,Вызовите InitAndSetConfig().,Полная инициализация общих параметров,Затем вызывайте только соответствующий другой интерфейс.
btnStartStopPlayback.setOnClickListener(new Button.OnClickListener() {
// @Override
public void onClick(View v) {
if (isPlaying) {
Log.i(TAG, "Stop playback stream++");
int iRet = libPlayer.SmartPlayerStopPlay(playerHandle);
if (iRet != 0) {
Log.e(TAG, "Call SmartPlayerStopPlay failed..");
return;
}
btnHardwareDecoder.setEnabled(true);
btnLowLatency.setEnabled(true);
if (!isRecording) {
btnPopInputUrl.setEnabled(true);
btnSetPlayBuffer.setEnabled(true);
btnFastStartup.setEnabled(true);
btnRecoderMgr.setEnabled(true);
libPlayer.SmartPlayerClose(playerHandle);
playerHandle = 0;
}
isPlaying = false;
btnStartStopPlayback.setText("Начать играть ");
if (is_enable_hardware_render_mode && sSurfaceView != null) {
sSurfaceView.setVisibility(View.GONE);
sSurfaceView.setVisibility(View.VISIBLE);
}
Log.i(TAG, "Stop playback stream--");
} else {
Log.i(TAG, "Start playback stream++");
if (!isRecording) {
InitAndSetConfig();
}
// Если для второго параметра установлено значение null, воспроизводится чистый звук.
libPlayer.SmartPlayerSetSurface(playerHandle, sSurfaceView);
libPlayer.SmartPlayerSetRenderScaleMode(playerHandle, 1);
//int render_format = 1;
//libPlayer.SmartPlayerSetSurfaceRenderFormat(playerHandle, render_format);
//int is_enable_anti_alias = 1;
//libPlayer.SmartPlayerSetSurfaceAntiAlias(playerHandle, is_enable_anti_alias);
if (isHardwareDecoder && is_enable_hardware_render_mode) {
libPlayer.SmartPlayerSetHWRenderMode(playerHandle, 1);
}
// External Render test
//libPlayer.SmartPlayerSetExternalRender(playerHandle, new RGBAExternalRender(imageSavePath));
//libPlayer.SmartPlayerSetExternalRender(playerHandle, new I420ExternalRender(imageSavePath));
libPlayer.SmartPlayerSetUserDataCallback(playerHandle, new UserDataCallback());
//libPlayer.SmartPlayerSetSEIDataCallback(playerHandle, new SEIDataCallback());
libPlayer.SmartPlayerSetAudioOutputType(playerHandle, 1);
if (isMute) {
libPlayer.SmartPlayerSetMute(playerHandle, isMute ? 1
: 0);
}
if (isHardwareDecoder) {
int isSupportHevcHwDecoder = libPlayer.SetSmartPlayerVideoHevcHWDecoder(playerHandle, 1);
int isSupportH264HwDecoder = libPlayer
.SetSmartPlayerVideoHWDecoder(playerHandle, 1);
Log.i(TAG, "isSupportH264HwDecoder: " + isSupportH264HwDecoder + ", isSupportHevcHwDecoder: " + isSupportHevcHwDecoder);
}
libPlayer.SmartPlayerSetLowLatencyMode(playerHandle, isLowLatency ? 1
: 0);
libPlayer.SmartPlayerSetFlipVertical(playerHandle, is_flip_vertical ? 1 : 0);
libPlayer.SmartPlayerSetFlipHorizontal(playerHandle, is_flip_horizontal ? 1 : 0);
libPlayer.SmartPlayerSetRotation(playerHandle, rotate_degrees);
libPlayer.SmartPlayerSetAudioVolume(playerHandle, curAudioVolume);
int iPlaybackRet = libPlayer
.SmartPlayerStartPlay(playerHandle);
if (iPlaybackRet != 0) {
Log.e(TAG, "Call SmartPlayerStartPlay failed..");
return;
}
btnStartStopPlayback.setText("Хватит играть ");
btnPopInputUrl.setEnabled(false);
btnPopInputKey.setEnabled(false);
btnSetPlayBuffer.setEnabled(false);
btnLowLatency.setEnabled(false);
btnFastStartup.setEnabled(false);
btnRecoderMgr.setEnabled(false);
isPlaying = true;
Log.i(TAG, "Start playback stream--");
}
}
});
Поскольку модули воспроизведения RTSP и RTMP, помимо обычной прямой трансляции, могут также записывать или извлекать потоки в реальном времени и пересылать их на RTMP-серверы или облегченные службы RTSP, поэтому базовая настройка параметров воспроизведения заканчивается записью и пересылкой. помещается в InitAndSetConfig() выполнить:
private void InitAndSetConfig() {
playerHandle = libPlayer.SmartPlayerOpen(myContext);
if (playerHandle == 0) {
Log.e(TAG, "surfaceHandle with nil..");
return;
}
libPlayer.SetSmartPlayerEventCallbackV2(playerHandle,
new EventHandeV2());
libPlayer.SmartPlayerSetBuffer(playerHandle, playBuffer);
// set report download скорость (по умолчанию — обратный вызов каждые 2 секунды) Пользователи могут самостоятельно настроить интервал отчетов.)
libPlayer.SmartPlayerSetReportDownloadSpeed(playerHandle, 1, 2);
libPlayer.SmartPlayerSetFastStartup(playerHandle, isFastStartup ? 1 : 0);
//Установить Тайм-аут RTSP
int rtsp_timeout = 10;
libPlayer.SmartPlayerSetRTSPTimeout(playerHandle, rtsp_timeout);
//Установить RTSP Автоматическое переключение режима TCP/UDP
int is_auto_switch_tcp_udp = 1;
libPlayer.SmartPlayerSetRTSPAutoSwitchTcpUdp(playerHandle, is_auto_switch_tcp_udp);
libPlayer.SmartPlayerSaveImageFlag(playerHandle, 1);
// It only used when playback RTSP stream..
// libPlayer.SmartPlayerSetRTSPTcpMode(playerHandle, 1);
// playbackUrl = "rtmp://localhost:1935/live/stream1";
if (playbackUrl == null) {
Log.e(TAG, "playback URL with NULL...");
return;
}
libPlayer.SmartPlayerSetUrl(playerHandle, playbackUrl);
// try_set_rtsp_url(playbackUrl);
}
Обработка обратного вызова события завершения воспроизведения EventHandle является очень важным средством обратной связи о состоянии. Помимо обратных вызовов состояния сети и буферизации, существуют также обратные вызовы для состояния записи, состояния моментального снимка и т. д.:
class EventHandeV2 implements NTSmartEventCallbackV2 {
@Override
public void onNTSmartEventCallbackV2(long handle, int id, long param1,
long param2, String param3, String param4, Object param5) {
String player_event = "";
switch (id) {
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STARTED:
player_event = "начинать..";
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTING:
player_event = «Соединяемся..»;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTION_FAILED:
player_event = «Соединение не удалось.»;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CONNECTED:
player_event = «Соединение успешно..»;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_DISCONNECTED:
player_event = «Соединение прервано.»;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STOP:
player_event = "Хватит играть..";
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RESOLUTION_INFO:
player_event = «Информация о разрешении: width: " + param1 + ", height: " + param2;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_NO_MEDIADATA_RECEIVED:
player_event = «Невозможно получить медиаданные, возможно, URL-адрес неправильный.»;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_SWITCH_URL:
player_event = "Переключить URL воспроизведения..";
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_CAPTURE_IMAGE:
player_event = "Снимок: " + param1 + " путь:" + param3;
if (param1 == 0)
player_event = player_event + ", Снимок сделан успешно";
else
player_event = player_event + ", Не удалось сделать снимок";
if (param4 != null && !param4.isEmpty())
player_event += (", user data:" + param4);
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RECORDER_START_NEW_FILE:
player_event = «[запись] запускает новый видеофайл : " + param3;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_ONE_RECORDER_FILE_FINISHED:
player_event = «[запись] создала видеофайл : " + param3;
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_START_BUFFERING:
Log.i(TAG, "Start Buffering");
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_BUFFERING:
Log.i(TAG, "Buffering:" + param1 + "%");
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_STOP_BUFFERING:
Log.i(TAG, "Stop Buffering");
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_DOWNLOAD_SPEED:
player_event = "download_speed:" + param1 + "Byte/s" + ", "
+ (param1 * 8 / 1000) + "kbps" + ", " + (param1 / 1024)
+ "KB/s";
break;
case NTSmartEventID.EVENT_DANIULIVE_ERC_PLAYER_RTSP_STATUS_CODE:
Log.e(TAG, "RTSP error code received, please make sure username/password is correct, error code:" + param1);
player_event = "RTSP error code:" + param1;
break;
}
if (player_event.length() > 0) {
Log.i(TAG, player_event);
Message message = new Message();
message.what = PLAYER_EVENT_MSG;
message.obj = player_event;
handler.sendMessage(message);
}
}
}
Если РТСП、RTMPпотокнуждаться Видео:
btnStartStopRecorder.setOnClickListener(new Button.OnClickListener() {
// @Override
public void onClick(View v) {
if (isRecording) {
int iRet = libPlayer.SmartPlayerStopRecorder(playerHandle);
if (iRet != 0) {
Log.e(TAG, "Call SmartPlayerStopRecorder failed..");
return;
}
if (!isPlaying) {
btnPopInputUrl.setEnabled(true);
btnSetPlayBuffer.setEnabled(true);
btnFastStartup.setEnabled(true);
btnRecoderMgr.setEnabled(true);
libPlayer.SmartPlayerClose(playerHandle);
playerHandle = 0;
}
btnStartStopRecorder.setText(" Начать запись");
isRecording = false;
} else {
Log.i(TAG, "onClick start recorder..");
if (!isPlaying) {
InitAndSetConfig();
}
ConfigRecorderFunction();
int startRet = libPlayer.SmartPlayerStartRecorder(playerHandle);
if (startRet != 0) {
Log.e(TAG, "Failed to start recorder.");
return;
}
btnPopInputUrl.setEnabled(false);
btnSetPlayBuffer.setEnabled(false);
btnFastStartup.setEnabled(false);
btnRecoderMgr.setEnabled(false);
isRecording = true;
btnStartStopRecorder.setText("Остановить запись");
}
}
});
в,Настройки параметров конфигурации записи, такие как Вниз,В дополнение к демонстрации интерфейса Вниз face,Вы также можете настроить запись только видео или аудио:
void ConfigRecorderFunction() {
if (libPlayer != null) {
int is_rec_trans_code = 1;
libPlayer.SmartPlayerSetRecorderAudioTranscodeAAC(playerHandle, is_rec_trans_code);
if (recDir != null && !recDir.isEmpty()) {
int ret = libPlayer.SmartPlayerCreateFileDirectory(recDir);
if (0 == ret) {
if (0 != libPlayer.SmartPlayerSetRecorderDirectory(
playerHandle, recDir)) {
Log.e(TAG, "Set recoder dir failed , path:" + recDir);
return;
}
if (0 != libPlayer.SmartPlayerSetRecorderFileMaxSize(
playerHandle, 200)) {
Log.e(TAG,
"SmartPublisherSetRecorderFileMaxSize failed.");
return;
}
} else {
Log.e(TAG, "Create recorder dir failed, path:" + recDir);
}
}
}
}
Чтобы играть во время Скриншота в первое время:
btnCaptureImage.setOnClickListener(new Button.OnClickListener() {
@SuppressLint("SimpleDateFormat")
public void onClick(View v) {
if (0 == playerHandle)
return;
if (null == capture_image_date_format_)
capture_image_date_format_ = new SimpleDateFormat("yyyyMMdd_HHmmss_SSS");
String timestamp = capture_image_date_format_.format(new Date());
String imageFileName = timestamp;
String image_path = imageSavePath + "/" + imageFileName;
int quality;
boolean is_jpeg = true;
if (is_jpeg) {
image_path += ".jpeg";
quality = 100;
}
else {
image_path += ".png";
quality = 100;
}
int capture_ret = libPlayer.CaptureImage(playerHandle,is_jpeg?0:1, quality, image_path, "test cix");
Log.i(TAG, "capture image ret:" + capture_ret + ", file:" + image_path);
}
});
Если вам нужно перевернуть видео по горизонтали, вертикали или повернуть:
btnFlipVertical.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
is_flip_vertical = !is_flip_vertical;
if (is_flip_vertical) {
btnFlipVertical.setText("Отменить переворот");
} else {
btnFlipVertical.setText("вертикальная инверсия");
}
if (playerHandle != 0) {
libPlayer.SmartPlayerSetFlipVertical(playerHandle,
is_flip_vertical ? 1 : 0);
}
}
});
btnFlipHorizontal.setOnClickListener(new Button.OnClickListener() {
public void onClick(View v) {
is_flip_horizontal = !is_flip_horizontal;
if (is_flip_horizontal) {
btnFlipHorizontal.setText("Отменить переворот");
} else {
btnFlipHorizontal.setText("горизонтальный разворот");
}
if (playerHandle != 0) {
libPlayer.SmartPlayerSetFlipHorizontal(playerHandle,is_flip_horizontal ? 1:0);
}
}
});
btnRotation.setOnClickListener(new Button.OnClickListener() {
общественная недействительность onClick (Просмотр v) {
вращать_градусы += 90;
вращать_градусы = вращать_градусы% 360;
если (0 == поворот_градусов) {
btnRotation.setText("вращать90степень");
} else if (90 == Rotate_grades) {
btnRotation.setText("вращать180степень");
} else if (180 == Rotate_grades) {
btnRotation.setText("вращать270 градусов");
} else if (270 == Rotate_grades) {
btnRotation.setText("Нетвращать");
}
если (playerHandle != 0) {
libPlayer.SmartPlayerSetRotation(playerHandle,
rotate_degrees);
}
}
});
При onDestroy() остановите воспроизведение, запись и отпустите дескриптор экземпляра проигрывателя:
@Override
protected void onDestroy() {
Log.i(TAG, "Run into activity destory++");
if (playerHandle != 0) {
if (isPlaying) {
libPlayer.SmartPlayerStopPlay(playerHandle);
}
if (isRecording) {
libPlayer.SmartPlayerStopRecorder(playerHandle);
}
libPlayer.SmartPlayerClose(playerHandle);
playerHandle = 0;
}
super.onDestroy();
finish();
System.exit(0);
}
Вышеупомянутый процесс является грубым. Если вам нужно воспроизвести несколько экземпляров, вы можете сделать простую инкапсуляцию. Эффект от нескольких экземпляров следующий:
Эталонный код инкапсуляции LibPlayerWrapper.java выглядит следующим образом. Если вам нужны дополнительные функции, просто добавьте их в соответствии со структурой дизайна:
/*
* LibPlayerWrapper.java.java
* Author: daniusdk.com
*/
package com.daniulive.smartplayer;
import android.content.Context;
import android.util.Log;
import android.view.Surface;
import android.view.SurfaceView;
import android.view.View;
import com.eventhandle.NTSmartEventCallbackV2;
import java.lang.ref.WeakReference;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
public class LibPlayerWrapper {
private static String TAG = "NTLogLibPlayerW";
private static final int OK = 0;
private WeakReference<Context> context_;
private final ReadWriteLock rw_lock_ = new ReentrantReadWriteLock(true);
private final java.util.concurrent.locks.Lock write_lock_ = rw_lock_.writeLock();
private final java.util.concurrent.locks.Lock read_lock_ = rw_lock_.readLock();
private SmartPlayerJniV2 lib_player_;
private volatile long native_handle_;
private View view_;
private volatile boolean is_playing_;
private volatile boolean is_recording_;
private WeakReference<EventListener> event_listener_;
public LibPlayerWrapper(SmartPlayerJniV2 lib_player, Context context, EventListener listener) {
if (!empty())
throw new IllegalStateException("it is not empty");
if (null == lib_player)
throw new NullPointerException("lib_player is null");
this.lib_player_ = lib_player;
if (context != null)
this.context_ = new WeakReference<>(context);
if (listener == null ) {
this.event_listener_ = null;
}
else {
this.event_listener_ = new WeakReference<>(listener);
}
}
private void clear_all_playing_flags() {
this.is_playing_ = false;
this.is_recording_ = false;
}
public void set(long handle) {
if (!empty())
throw new IllegalStateException("it is not empty");
write_lock_.lock();
try {
clear_all_playing_flags();
this.native_handle_ = handle;
} finally {
write_lock_.unlock();
}
Log.i(TAG, "set native_handle:" + handle);
}
public void SetView(View view) {
Log.i(TAG, "SetView: " + view);
this.view_ = view;
}
@Override
protected void finalize() throws Throwable {
try {
if (check_native_handle()) {
if(is_playing()) {
lib_player_.SmartPlayerStopPlay(get());
this.is_playing_ = false;
}
if(is_recording()) {
lib_player_.SmartPlayerStopRecorder(get());
this.is_recording_ = false;
}
lib_player_.SmartPlayerClose(this.native_handle_);
Log.i(TAG, "finalize close handle:" + this.native_handle_);
this.native_handle_ = 0;
}
}catch (Exception e) {
}
super.finalize();
}
public void release() {
if (empty())
return;
if(is_playing())
StopPlayer();
if (is_recording())
StopRecorder();
long handle;
write_lock_.lock();
try {
handle = this.native_handle_;
this.native_handle_ = 0;
clear_all_playing_flags();
} finally {
write_lock_.unlock();
}
if (lib_player_ != null && handle != 0)
lib_player_.SmartPlayerClose(handle);
}
public boolean try_release() {
if (empty())
return false;
if (is_player_running()) {
Log.i(TAG, "try_release it is running, native_handle:" + get());
return false;
}
long handle;
write_lock_.lock();
try {
if (is_player_running())
return false;
handle = this.native_handle_;
this.native_handle_ = 0;
} finally {
write_lock_.unlock();
}
if (lib_player_ != null && handle != 0)
lib_player_.SmartPlayerClose(handle);
return true;
}
public final boolean empty() { return 0 == this.native_handle_; }
public final long get() { return this.native_handle_; }
public View get_view() {return this.view_;}
public final boolean check_native_handle() {
return this.lib_player_ != null && this.native_handle_ != 0;
}
public final boolean is_playing() { return is_playing_; }
public final boolean is_recording() { return is_recording_; }
public final boolean is_player_running() { return is_playing_ || is_recording_; }
private boolean isValidRtspOrRtmpUrl(String url) {
if (url == null || url.isEmpty()) {
return false;
}
return url.trim().startsWith("rtsp://") || url.startsWith("rtmp://");
}
private EventListener getListener() {
if ( this.event_listener_ == null )
return null;
return this.event_listener_.get();
}
protected final Context application_context() {
if (null == context_)
return null;
return context_.get();
}
public boolean OpenPlayerHandle(String playback_url, int play_buffer, int is_using_tcp) {
if (check_native_handle())
return true;
if(!isValidRtspOrRtmpUrl(playback_url))
return false;
long handle = lib_player_.SmartPlayerOpen(application_context());
if (0==handle) {
Log.e(TAG, "sdk open failed!");
return false;
}
lib_player_.SetSmartPlayerEventCallbackV2(handle, new EventHandleV2());
lib_player_.SmartPlayerSetBuffer(handle, play_buffer);
// set report download скорость (по умолчанию — обратный вызов каждые 2 секунды) Пользователи могут самостоятельно настроить интервал отчетов.)
lib_player_.SmartPlayerSetReportDownloadSpeed(handle, 1, 4);
boolean isFastStartup = true;
lib_player_.SmartPlayerSetFastStartup(handle, isFastStartup ? 1 : 0);
//Установить Тайм-аут RTSP
int rtsp_timeout = 10;
lib_player_.SmartPlayerSetRTSPTimeout(handle, rtsp_timeout);
//Установить RTSP Автоматическое переключение режима TCP/UDP
int is_auto_switch_tcp_udp = 1;
lib_player_.SmartPlayerSetRTSPAutoSwitchTcpUdp(handle, is_auto_switch_tcp_udp);
lib_player_.SmartPlayerSaveImageFlag(handle, 1);
// It only used when playback RTSP stream..
lib_player_.SmartPlayerSetRTSPTcpMode(handle, is_using_tcp);
lib_player_.DisableEnhancedRTMP(handle, 0);
lib_player_.SmartPlayerSetUrl(handle, playback_url);
set(handle);
return true;
}
private void SetPlayerParam(boolean is_hardware_decoder, boolean is_enable_hardware_render_mode, boolean is_mute)
{
Surface surface = null;
int surface_codec_media_color_format = 0;
if (view_ != null && view_ instanceof SurfaceView && ((SurfaceView) view_).getHolder() != null)
surface = ((SurfaceView) view_).getHolder().getSurface();
lib_player_.SetSurface(get(), surface, surface_codec_media_color_format, 0, 0);
lib_player_.SmartPlayerSetRenderScaleMode(get(), 1);
//int render_format = 1;
//lib_player.SmartPlayerSetSurfaceRenderFormat(handle, render_format);
//int is_enable_anti_alias = 1;
//lib_player.SmartPlayerSetSurfaceAntiAlias(handle, is_enable_anti_alias);
if (is_hardware_decoder && is_enable_hardware_render_mode) {
lib_player_.SmartPlayerSetHWRenderMode(get(), 1);
}
lib_player_.SmartPlayerSetAudioOutputType(get(), 1);
lib_player_.SmartPlayerSetMute(get(), is_mute ? 1 : 0);
if (is_hardware_decoder) {
int isSupportHevcHwDecoder = lib_player_.SetSmartPlayerVideoHevcHWDecoder(get(), 1);
int isSupportH264HwDecoder = lib_player_.SetSmartPlayerVideoHWDecoder(get(), 1);
Log.i(TAG, "isSupportH264HwDecoder: " + isSupportH264HwDecoder + ", isSupportHevcHwDecoder: " + isSupportHevcHwDecoder);
}
boolean isLowLatency = true;
lib_player_.SmartPlayerSetLowLatencyMode(get(), isLowLatency ? 1 : 0);
boolean is_flip_vertical = false;
lib_player_.SmartPlayerSetFlipVertical(get(), is_flip_vertical ? 1 : 0);
boolean is_flip_horizontal = false;
lib_player_.SmartPlayerSetFlipHorizontal(get(), is_flip_horizontal ? 1 : 0);
int rotate_degrees = 0;
lib_player_.SmartPlayerSetRotation(get(), rotate_degrees);
int curAudioVolume = 100;
lib_player_.SmartPlayerSetAudioVolume(get(), curAudioVolume);
}
class EventHandleV2 implements NTSmartEventCallbackV2 {
@Override
public void onNTSmartEventCallbackV2(long handle, int id, long param1,
long param2, String param3, String param4, Object param5) {
if(event_listener_.get() != null)
{
event_listener_.get().onPlayerEventCallback(handle, id, param1, param2, param3, param4, param5);
}
}
}
public boolean SetMute(boolean is_mute) {
if (!check_native_handle())
return false;
return OK == lib_player_.SmartPlayerSetMute(get(), is_mute? 1 : 0);
}
public boolean SetInputAudioVolume(int volume) {
if (!check_native_handle())
return false;
return OK == lib_player_.SmartPlayerSetAudioVolume(get(), volume);
}
public boolean CaptureImage(int compress_format, int quality, String file_name, String user_data_string) {
if (!check_native_handle())
return false;
return OK == lib_player_.CaptureImage(get(), compress_format, quality, file_name, user_data_string);
}
public boolean StartPlayer(boolean is_hardware_decoder, boolean is_enable_hardware_render_mode, boolean is_mute) {
if (is_playing()) {
Log.e(TAG, "already playing, native_handle:" + get());
return false;
}
SetPlayerParam(is_hardware_decoder, is_enable_hardware_render_mode, is_mute);
int ret = lib_player_.SmartPlayerStartPlay(get());
if (ret != OK) {
Log.e(TAG, "call StartPlay failed, native_handle:" + get() + ", ret:" + ret);
return false;
}
write_lock_.lock();
try {
this.is_playing_ = true;
} finally {
write_lock_.unlock();
}
Log.i(TAG, "call StartPlayer OK, native_handle:" + get());
return true;
}
public boolean StopPlayer() {
if (!check_native_handle())
return false;
if (!is_playing()) {
Log.w(TAG, "it's not playing, native_handle:" + get());
return false;
}
boolean is_need_call = false;
write_lock_.lock();
try {
if (this.is_playing_) {
this.is_playing_ = false;
is_need_call = true;
}
} finally {
write_lock_.unlock();
}
if (is_need_call)
lib_player_.SmartPlayerStopPlay(get());
return true;
}
public boolean ConfigRecorderParam(String rec_dir, int file_max_size, int is_transcode_aac,
int is_record_video, int is_record_audio) {
if(!check_native_handle())
return false;
if (null == rec_dir || rec_dir.isEmpty())
return false;
int ret = lib_player_.SmartPlayerCreateFileDirectory(rec_dir);
if (ret != 0) {
Log.e(TAG, "Create record dir failed, path:" + rec_dir);
return false;
}
if (lib_player_.SmartPlayerSetRecorderDirectory(get(), rec_dir) != 0) {
Log.e(TAG, "Set record dir failed , path:" + rec_dir);
return false;
}
if (lib_player_.SmartPlayerSetRecorderFileMaxSize(get(),file_max_size) != 0) {
Log.e(TAG, "SmartPlayerSetRecorderFileMaxSize failed.");
return false;
}
lib_player_.SmartPlayerSetRecorderAudioTranscodeAAC(get(), is_transcode_aac);
// Более детальный контроль записи, Обычно нет необходимости звонить
lib_player_.SmartPlayerSetRecorderVideo(get(), is_record_video);
lib_player_.SmartPlayerSetRecorderAudio(get(), is_record_audio);
return true;
}
public boolean StartRecorder() {
if (is_recording()) {
Log.e(TAG, "already recording, native_handle:" + get());
return false;
}
int ret = lib_player_.SmartPlayerStartRecorder(get());
if (ret != OK) {
Log.e(TAG, "call SmartPlayerStartRecorder failed, native_handle:" + get() + ", ret:" + ret);
return false;
}
write_lock_.lock();
try {
this.is_recording_ = true;
} finally {
write_lock_.unlock();
}
Log.i(TAG, "call SmartPlayerStartRecorder OK, native_handle:" + get());
return true;
}
public boolean StopRecorder() {
if (!check_native_handle())
return false;
if (!is_recording()) {
Log.w(TAG, "it's not recording, native_handle:" + get());
return false;
}
boolean is_need_call = false;
write_lock_.lock();
try {
if (this.is_recording_) {
this.is_recording_ = false;
is_need_call = true;
}
} finally {
write_lock_.unlock();
}
if (is_need_call)
lib_player_.SmartPlayerStopRecorder(get());
return true;
}
private static boolean is_null_or_empty(String val) {
return null == val || val.isEmpty();
}
}
Выше приведены инструкции по стыковке модулей прямых трансляций RTSP и RTMP на платформе Android.,до этого,Мы провели некоторые технические обсуждения SmartPlayer.,Из различных аспектов, таких как низкая задержка, обработка синхронизации аудио и видео, многоэкземплярная реализация, эффективность декодирования, занятость производительности, стыковка декодированных данных, запись видео, обработка сетевого дрожания и т. д.,Осуществили соответствующий обмен технологиями. Заинтересованные разработчики,Вы можете обсудить это с нами индивидуально.