remove everything of MediaPlayer

pull/209/head
xufuji456 3 years ago
parent 4d32a0b77d
commit 102e639831
  1. 2
      app/CMakeLists.txt
  2. 3
      app/proguard-rules.pro
  3. 28
      app/src/main/AndroidManifest.xml
  4. 499
      app/src/main/cpp/media_player.cpp
  5. 61
      app/src/main/cpp/packet_queue.cpp
  6. 37
      app/src/main/cpp/packet_queue.h
  7. 48
      app/src/main/java/com/frank/ffmpeg/MediaPlayer.java
  8. 103
      app/src/main/java/com/frank/ffmpeg/activity/MediaPlayerActivity.kt
  9. 39
      app/src/main/res/layout/activity_media_player.xml

@ -29,8 +29,6 @@ add_library( # Sets the name of the library.
src/main/cpp/opensl_audio_player.cpp src/main/cpp/opensl_audio_player.cpp
src/main/cpp/video_player.cpp src/main/cpp/video_player.cpp
src/main/cpp/ffmpeg_pusher.cpp src/main/cpp/ffmpeg_pusher.cpp
src/main/cpp/packet_queue.cpp
src/main/cpp/media_player.cpp
src/main/cpp/video_filter.c src/main/cpp/video_filter.c
src/main/cpp/fast_start.c src/main/cpp/fast_start.c
src/main/cpp/ffprobe_cmd.cpp src/main/cpp/ffprobe_cmd.cpp

@ -33,9 +33,6 @@
-keep public class com.frank.ffmpeg.FFmpegCmd { -keep public class com.frank.ffmpeg.FFmpegCmd {
} }
-keep public class com.frank.ffmpeg.MediaPlayer {
}
-keep public class com.frank.ffmpeg.Pusher { -keep public class com.frank.ffmpeg.Pusher {
} }

@ -16,7 +16,7 @@
<application <application
android:name=".FFmpegApplication" android:name=".FFmpegApplication"
android:allowBackup="true" android:fullBackupOnly="true"
android:icon="@mipmap/ic_launcher" android:icon="@mipmap/ic_launcher"
android:label="@string/app_name" android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round" android:roundIcon="@mipmap/ic_launcher_round"
@ -32,29 +32,23 @@
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> <!-- audio handle --> </activity>
<activity android:name=".activity.AudioHandleActivity" /> <!-- media handle --> <activity android:name=".activity.AudioHandleActivity" />
<activity android:name=".activity.MediaHandleActivity" /> <!-- video handle --> <activity android:name=".activity.MediaHandleActivity" />
<activity android:name=".activity.VideoHandleActivity" /> <!-- media player --> <activity android:name=".activity.VideoHandleActivity" />
<activity <activity android:name=".activity.PushActivity" />
android:name=".activity.MediaPlayerActivity"
android:screenOrientation="landscape" /> <!-- local pusher -->
<activity android:name=".activity.PushActivity" /> <!-- real time pusher -->
<activity <activity
android:name=".activity.LiveActivity" android:name=".activity.LiveActivity"
android:screenOrientation="portrait" /> <!-- filter effect --> android:screenOrientation="landscape" />
<activity <activity
android:name=".activity.FilterActivity" android:name=".activity.FilterActivity"
android:screenOrientation="landscape" /> <!-- video preview --> android:screenOrientation="landscape" />
<activity <activity
android:name=".activity.VideoPreviewActivity" android:name=".activity.VideoPreviewActivity" />
android:screenOrientation="portrait" /> <!-- probe media format -->
<activity <activity
android:name=".activity.ProbeFormatActivity" android:name=".activity.ProbeFormatActivity" />
android:screenOrientation="portrait" />
<activity <activity
android:name=".activity.AudioEffectActivity" android:name=".activity.AudioEffectActivity" />
android:screenOrientation="portrait" />
<activity android:name=".activity.AudioPlayActivity" /> <activity android:name=".activity.AudioPlayActivity" />
<activity android:name=".activity.EqualizerActivity" /> <activity android:name=".activity.EqualizerActivity" />
</application> </application>

@ -1,499 +0,0 @@
//
// Created by frank on 2018/2/3.
//
#include <android/native_window.h>
#include <android/native_window_jni.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <jni.h>
#ifdef __cplusplus
extern "C" {
#endif
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libavutil/imgutils.h"
#include "libavutil/time.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "packet_queue.h"
#include "ffmpeg_jni_define.h"
#include "include/libavcodec/jni.h"
#ifdef __cplusplus
}
#endif
#define TAG "MediaPlayer"
#define MAX_AUDIO_FRAME_SIZE 48000 * 4
#define PACKET_SIZE 50
#define MIN_SLEEP_TIME_US 1000ll
#define AUDIO_TIME_ADJUST_US -200000ll
struct timeval now;
struct timespec timeout;
typedef struct MediaPlayer{
AVFormatContext* format_context;
int video_stream_index;
int audio_stream_index;
AVCodecContext* video_codec_context;
AVCodecContext* audio_codec_context;
AVCodec* video_codec;
AVCodec* audio_codec;
ANativeWindow* native_window;
uint8_t* buffer;
AVFrame* yuv_frame;
AVFrame* rgba_frame;
int video_width;
int video_height;
SwrContext* swrContext;
int out_channel_nb;
int out_sample_rate;
enum AVSampleFormat out_sample_fmt;
jobject audio_track;
jmethodID audio_track_write_mid;
uint8_t* audio_buffer;
AVFrame* audio_frame;
AVPacketQueue* packets[2];
pthread_mutex_t mutex;
pthread_cond_t cond;
int64_t start_time;
int64_t audio_clock;
pthread_t write_thread;
pthread_t video_thread;
pthread_t audio_thread;
}MediaPlayer;
typedef struct Decoder{
MediaPlayer* player;
int stream_index;
}Decoder;
JavaVM* javaVM;
MediaPlayer* player;
jint JNICALL JNI_OnLoad(JavaVM* vm, void* reserved){
javaVM = vm;
av_jni_set_java_vm(vm, nullptr);// set JavaVM into FFmpeg
return JNI_VERSION_1_6;
}
//init player
int init_input_format_context(MediaPlayer* player, const char* file_name){
//register all modules
av_register_all();
//alloc format context
player->format_context = avformat_alloc_context();
//open the input file
if(avformat_open_input(&player->format_context, file_name, nullptr, nullptr)!=0) {
LOGE(TAG, "Couldn't open file:%s\n", file_name);
return -1;
}
//find the info of all streams
if(avformat_find_stream_info(player->format_context, nullptr)<0) {
LOGE(TAG, "Couldn't find stream information.");
return -1;
}
//find the index of audio and video stream
int i;
player->video_stream_index = -1;
player->audio_stream_index = -1;
for (i = 0; i < player->format_context->nb_streams; i++) {
if (player->format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO
&& player->video_stream_index < 0) {
player->video_stream_index = i;
} else if (player->format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO
&& player->audio_stream_index < 0) {
player->audio_stream_index = i;
}
}
if(player->video_stream_index==-1) {
LOGE(TAG, "couldn't find a video stream.");
return -1;
}
if(player->audio_stream_index==-1) {
LOGE(TAG, "couldn't find a audio stream.");
return -1;
}
LOGI(TAG, "video_stream_index=%d", player->video_stream_index);
LOGI(TAG, "audio_stream_index=%d", player->audio_stream_index);
return 0;
}
//open decoder
int init_codec_context(MediaPlayer* player){
//get codec context
player->video_codec_context = player->format_context->streams[player->video_stream_index]->codec;
//find audio and video decoder
player->video_codec = avcodec_find_decoder(player->video_codec_context->codec_id);
if(player->video_codec == nullptr) {
LOGE(TAG, "couldn't find video Codec.");
return -1;
}
if(avcodec_open2(player->video_codec_context, player->video_codec, nullptr) < 0) {
LOGE(TAG, "Couldn't open video codec.");
return -1;
}
player->audio_codec_context = player->format_context->streams[player->audio_stream_index]->codec;
player->audio_codec = avcodec_find_decoder(player->audio_codec_context->codec_id);
if( player->audio_codec == nullptr) {
LOGE(TAG, "couldn't find audio Codec.");
return -1;
}
if(avcodec_open2(player->audio_codec_context, player->audio_codec, nullptr) < 0) {
LOGE(TAG, "Couldn't open audio codec.");
return -1;
}
// width and height
player->video_width = player->video_codec_context->width;
player->video_height = player->video_codec_context->height;
return 0;
}
void video_player_prepare(MediaPlayer* player, JNIEnv* env, jobject surface){
// get native window
player->native_window = ANativeWindow_fromSurface(env, surface);
}
//get current playing time
int64_t get_play_time(MediaPlayer* player){
return (int64_t)(av_gettime() - player->start_time);
}
/**
* audio and video synchronization
*/
void player_wait_for_frame(MediaPlayer *player, int64_t stream_time) {
pthread_mutex_lock(&player->mutex);
for(;;){
int64_t current_video_time = get_play_time(player);
int64_t sleep_time = stream_time - current_video_time;
if (sleep_time < -300000ll) {
// 300 ms late
int64_t new_value = player->start_time - sleep_time;
player->start_time = new_value;
pthread_cond_broadcast(&player->cond);
}
if (sleep_time <= MIN_SLEEP_TIME_US) {
// We do not need to wait if time is slower then minimal sleep time
break;
}
if (sleep_time > 500000ll) {
// if sleep time is bigger then 500ms just sleep this 500ms
// and check everything again
sleep_time = 500000ll;
}
//TODO: waiting util time out
// pthread_cond_timeout_np(&player->cond, &player->mutex,
// (unsigned int) (sleep_time / 1000ll));
gettimeofday(&now, nullptr);
timeout.tv_sec = now.tv_sec;
timeout.tv_nsec = static_cast<long>((now.tv_usec + sleep_time) * 1000);
pthread_cond_timedwait(&player->cond, &player->mutex, &timeout);
}
pthread_mutex_unlock(&player->mutex);
}
//decode video packet as a frame
int decode_video(MediaPlayer* player, AVPacket* packet){
ANativeWindow_setBuffersGeometry(player->native_window, player->video_width,
player->video_height, WINDOW_FORMAT_RGBA_8888);
ANativeWindow_Buffer windowBuffer;
player->yuv_frame = av_frame_alloc();
player->rgba_frame = av_frame_alloc();
if(player->rgba_frame == nullptr || player->yuv_frame == nullptr) {
LOGE(TAG, "Couldn't allocate video frame.");
return -1;
}
// get buffer size, the format is RGBA
int numBytes=av_image_get_buffer_size(AV_PIX_FMT_RGBA, player->video_width, player->video_height, 1);
player->buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t));
av_image_fill_arrays(player->rgba_frame->data, player->rgba_frame->linesize, player->buffer, AV_PIX_FMT_RGBA,
player->video_width, player->video_height, 1);
struct SwsContext *sws_ctx = sws_getContext(
player->video_width,
player->video_height,
player->video_codec_context->pix_fmt,
player->video_width,
player->video_height,
AV_PIX_FMT_RGBA,
SWS_BILINEAR,
nullptr,
nullptr,
nullptr);
int frameFinished;
//decode video frame
int ret = avcodec_decode_video2(player->video_codec_context, player->yuv_frame, &frameFinished, packet);
if(ret < 0){
LOGE(TAG, "avcodec_decode_video2 error...");
return -1;
}
if (frameFinished) {
// lock native window
ANativeWindow_lock(player->native_window, &windowBuffer, 0);
// yuv to rgba
sws_scale(sws_ctx, (uint8_t const * const *)player->yuv_frame->data,
player->yuv_frame->linesize, 0, player->video_height,
player->rgba_frame->data, player->rgba_frame->linesize);
uint8_t * dst = static_cast<uint8_t *>(windowBuffer.bits);
int dstStride = windowBuffer.stride * 4;
uint8_t * src = player->rgba_frame->data[0];
int srcStride = player->rgba_frame->linesize[0];
// copy data to the target buffer
int h;
for (h = 0; h < player->video_height; h++) {
memcpy(dst + h * dstStride, src + h * srcStride, (size_t) srcStride);
}
//calculate pts
int64_t pts = av_frame_get_best_effort_timestamp(player->yuv_frame);
AVStream *stream = player->format_context->streams[player->video_stream_index];
//convert to real time
int64_t time = av_rescale_q(pts, stream->time_base, AV_TIME_BASE_Q);
//synchronize
player_wait_for_frame(player, time);
ANativeWindow_unlockAndPost(player->native_window);
}
return 0;
}
//init audio decoder
void audio_decoder_prepare(MediaPlayer* player) {
player->swrContext = swr_alloc();
//input format
enum AVSampleFormat in_sample_fmt = player->audio_codec_context->sample_fmt;
//output format
player->out_sample_fmt = AV_SAMPLE_FMT_S16;
//input sampleRate
int in_sample_rate = player->audio_codec_context->sample_rate;
//output sampleRate
player->out_sample_rate = in_sample_rate;
//channel layout (stereo by default)
uint64_t in_ch_layout = player->audio_codec_context->channel_layout;
//output channel layout
uint64_t out_ch_layout = AV_CH_LAYOUT_STEREO;
swr_alloc_set_opts(player->swrContext,
out_ch_layout, player->out_sample_fmt, player->out_sample_rate,
in_ch_layout, in_sample_fmt, in_sample_rate,
0, nullptr);
swr_init(player->swrContext);
player->out_channel_nb = av_get_channel_layout_nb_channels(out_ch_layout);
}
void audio_player_prepare(MediaPlayer* player, JNIEnv* env, jobject thiz){
jclass player_class = env->GetObjectClass(thiz);
if(!player_class){
LOGE(TAG, "player_class not found...");
}
//get AudioTrack by reflection
jmethodID audio_track_method = env->GetMethodID(
player_class,"createAudioTrack","(II)Landroid/media/AudioTrack;");
if(!audio_track_method){
LOGE(TAG, "audio_track_method not found...");
}
jobject audio_track = env->CallObjectMethod(
thiz, audio_track_method, player->out_sample_rate, player->out_channel_nb);
jclass audio_track_class = env->GetObjectClass(audio_track);
jmethodID audio_track_play_mid = env->GetMethodID(audio_track_class,"play","()V");
env->CallVoidMethod(audio_track, audio_track_play_mid);
player->audio_track = env->NewGlobalRef(audio_track);
player->audio_track_write_mid = env->GetMethodID(audio_track_class,"write","([BII)I");
//malloc buffer
player->audio_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE);
player->audio_frame = av_frame_alloc();
}
//audio decode function
int decode_audio(MediaPlayer* player, AVPacket* packet){
int got_frame = 0, ret;
ret = avcodec_decode_audio4(player->audio_codec_context, player->audio_frame, &got_frame, packet);
if(ret < 0){
LOGE(TAG, "avcodec_decode_audio4 error...");
return -1;
}
//decode success
if(got_frame > 0){
//convert audio format
swr_convert(player->swrContext,
&player->audio_buffer,
MAX_AUDIO_FRAME_SIZE,
(const uint8_t **)player->audio_frame->data,
player->audio_frame->nb_samples);
int out_buffer_size = av_samples_get_buffer_size(nullptr,
player->out_channel_nb,
player->audio_frame->nb_samples,
player->out_sample_fmt,
1);
//synchronize
int64_t pts = packet->pts;
if (pts != AV_NOPTS_VALUE) {
AVStream *stream = player->format_context->streams[player->audio_stream_index];
player->audio_clock = av_rescale_q(pts, stream->time_base, AV_TIME_BASE_Q);
player_wait_for_frame(player, player->audio_clock + AUDIO_TIME_ADJUST_US);
}
if(javaVM != nullptr){
JNIEnv * env;
javaVM->AttachCurrentThread(&env, nullptr);
jbyteArray audio_sample_array = env->NewByteArray(out_buffer_size);
jbyte* sample_byte_array = env->GetByteArrayElements(audio_sample_array, nullptr);
memcpy(sample_byte_array, player->audio_buffer, (size_t) out_buffer_size);
env->ReleaseByteArrayElements(audio_sample_array,sample_byte_array,0);
//call write method of AudioTrack to play
env->CallIntMethod(player->audio_track, player->audio_track_write_mid,
audio_sample_array,0,out_buffer_size);
//release local reference
env->DeleteLocalRef(audio_sample_array);
}
}
if(javaVM != NULL){
javaVM->DetachCurrentThread();
}
return 0;
}
void init_queue(MediaPlayer* player, int size){
int i;
for (i = 0; i < 2; ++i) {
AVPacketQueue* queue = queue_init(size);
player->packets[i] = queue;
}
}
void delete_queue(MediaPlayer* player){
int i;
for (i = 0; i < 2; ++i) {
queue_free(player->packets[i]);
}
}
//the thread of write packet
void* write_packet_to_queue(void* arg){
MediaPlayer* player = (MediaPlayer*)arg;
AVPacket packet, *pkt = &packet;
int ret;
for(;;){
ret = av_read_frame(player->format_context, pkt);
if(ret < 0){
break;
}
if(pkt->stream_index == player->video_stream_index || pkt->stream_index == player->audio_stream_index){
AVPacketQueue *queue = player->packets[pkt->stream_index];
pthread_mutex_lock(&player->mutex);
AVPacket* data = static_cast<AVPacket *>(queue_push(queue, &player->mutex,
&player->cond));
pthread_mutex_unlock(&player->mutex);
*data = packet;
}
}
}
//the thread of decoding
void* decode_func(void* arg){
Decoder *decoder_data = (Decoder*)arg;
MediaPlayer *player = decoder_data->player;
int stream_index = decoder_data->stream_index;
AVPacketQueue *queue = player->packets[stream_index];
int ret = 0;
for(;;) {
pthread_mutex_lock(&player->mutex);
AVPacket *packet = (AVPacket*)queue_pop(queue, &player->mutex, &player->cond);
pthread_mutex_unlock(&player->mutex);
if(stream_index == player->video_stream_index) {//video stream
ret = decode_video(player, packet);
} else if(stream_index == player->audio_stream_index) {//audio stream
ret = decode_audio(player, packet);
}
av_packet_unref(packet);
if(ret < 0){
break;
}
}
}
MEDIA_PLAYER_FUNC(jint, setup, jstring filePath, jobject surface){
const char *file_name = env->GetStringUTFChars(filePath, JNI_FALSE);
int ret;
player = static_cast<MediaPlayer *>(malloc(sizeof(MediaPlayer)));
if(player == nullptr){
return -1;
}
ret = init_input_format_context(player, file_name);
if(ret < 0){
return ret;
}
ret = init_codec_context(player);
if(ret < 0){
return ret;
}
//init surface
video_player_prepare( player, env, surface);
//init params of player
audio_decoder_prepare(player);
//init player
audio_player_prepare(player, env, thiz);
//init queue
init_queue(player, PACKET_SIZE);
return 0;
}
MEDIA_PLAYER_FUNC(jint, play){
pthread_mutex_init(&player->mutex, nullptr);
pthread_cond_init(&player->cond, nullptr);
pthread_create(&player->write_thread, nullptr, write_packet_to_queue, (void*)player);
sleep(1);
player->start_time = 0;
Decoder data1 = {player, player->video_stream_index}, *decoder_data1 = &data1;
pthread_create(&player->video_thread, nullptr, decode_func, (void*)decoder_data1);
Decoder data2 = {player, player->audio_stream_index}, *decoder_data2 = &data2;
pthread_create(&player->audio_thread, nullptr, decode_func, (void*)decoder_data2);
pthread_join(player->write_thread, nullptr);
pthread_join(player->video_thread, nullptr);
pthread_join(player->audio_thread, nullptr);
return 0;
}
MEDIA_PLAYER_FUNC(void, release){
free(player->audio_track);
free(player->audio_track_write_mid);
av_free(player->buffer);
av_free(player->rgba_frame);
av_free(player->yuv_frame);
av_free(player->audio_buffer);
av_free(player->audio_frame);
avcodec_free_context(&player->video_codec_context);
avcodec_free_context(&player->audio_codec_context);
avformat_close_input(&player->format_context);
ANativeWindow_release(player->native_window);
delete_queue(player);
pthread_cond_destroy(&player->cond);
pthread_mutex_destroy(&player->mutex);
free(player);
javaVM->DestroyJavaVM();
}

@ -1,61 +0,0 @@
//
// Created by frank on 2018/2/3.
//
#include "packet_queue.h"
#include <stdlib.h>
#include <libavcodec/avcodec.h>
AVPacketQueue *queue_init(int size) {
AVPacketQueue *queue = static_cast<AVPacketQueue *>(malloc(sizeof(AVPacketQueue)));
queue->size = size;
queue->next_to_read = 0;
queue->next_to_write = 0;
int i;
queue->packets = static_cast<void **>(malloc(sizeof(*queue->packets) * size));
for (i = 0; i < size; i++) {
queue->packets[i] = malloc(sizeof(AVPacket));
}
return queue;
}
void queue_free(AVPacketQueue *queue) {
int i;
for (i = 0; i < queue->size; i++) {
free(queue->packets[i]);
}
free(queue->packets);
free(queue);
}
int queue_next(AVPacketQueue *queue, int current) {
return (current + 1) % queue->size;
}
void *queue_push(AVPacketQueue *queue, pthread_mutex_t *mutex, pthread_cond_t *cond) {
int current = queue->next_to_write;
int next_to_write;
for (;;) {
next_to_write = queue_next(queue, current);
if (next_to_write != queue->next_to_read) {
break;
}
pthread_cond_wait(cond, mutex);
}
queue->next_to_write = next_to_write;
pthread_cond_broadcast(cond);
return queue->packets[current];
}
void *queue_pop(AVPacketQueue *queue, pthread_mutex_t *mutex, pthread_cond_t *cond) {
int current = queue->next_to_read;
for (;;) {
if (queue->next_to_write != queue->next_to_read) {
break;
}
pthread_cond_wait(cond, mutex);
}
queue->next_to_read = queue_next(queue, current);
pthread_cond_broadcast(cond);
return queue->packets[current];
}

@ -1,37 +0,0 @@
//
// Created by frank on 2018/2/3.
//
#ifndef PACKET_QUEUE_H
#define PACKET_QUEUE_H
#include <pthread.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef struct AVPacketQueue {
//the size of queue
int size;
//packet array
void **packets;
//the packet next to write
int next_to_write;
//the packet next to read
int next_to_read;
} AVPacketQueue;
AVPacketQueue *queue_init(int size);
void queue_free(AVPacketQueue *queue);
void *queue_push(AVPacketQueue *queue, pthread_mutex_t *mutex, pthread_cond_t *cond);
void *queue_pop(AVPacketQueue *queue, pthread_mutex_t *mutex, pthread_cond_t *cond);
#endif //PACKET_QUEUE_H
#ifdef __cplusplus
}
#endif

@ -1,48 +0,0 @@
package com.frank.ffmpeg;
import android.media.AudioFormat;
import android.media.AudioManager;
import android.media.AudioTrack;
/**
* Using FFmpeg to play media
* Created by frank on 2018/2/12.
*/
public class MediaPlayer {
static {
System.loadLibrary("media-handle");
}
public native int setup(String filePath, Object surface);
public native int play();
public native void release();
/**
* Create an AudioTrack instance for JNI calling
*
* @param sampleRate sampleRate
* @param channels channel layout
* @return AudioTrack
*/
public AudioTrack createAudioTrack(int sampleRate, int channels) {
int audioFormat = AudioFormat.ENCODING_PCM_16BIT;
int channelConfig;
if (channels == 1) {
channelConfig = android.media.AudioFormat.CHANNEL_OUT_MONO;
} else if (channels == 2) {
channelConfig = android.media.AudioFormat.CHANNEL_OUT_STEREO;
} else {
channelConfig = android.media.AudioFormat.CHANNEL_OUT_STEREO;
}
int bufferSizeInBytes = AudioTrack.getMinBufferSize(sampleRate, channelConfig, audioFormat);
return new AudioTrack(AudioManager.STREAM_MUSIC, sampleRate, channelConfig, audioFormat,
bufferSizeInBytes, AudioTrack.MODE_STREAM);
}
}

@ -1,103 +0,0 @@
package com.frank.ffmpeg.activity
import android.os.Bundle
import android.util.Log
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View
import android.widget.Button
import com.frank.ffmpeg.MediaPlayer
import com.frank.ffmpeg.R
import com.frank.ffmpeg.util.FileUtil
/**
* mediaPlayer, which decode by software
* Created by frank on 2018/2/12.
*/
class MediaPlayerActivity : BaseActivity(), SurfaceHolder.Callback {
private var surfaceHolder: SurfaceHolder? = null
private var mediaPlayer: MediaPlayer? = null
private var surfaceCreated: Boolean = false
private var btnSelectFile: Button? = null
override val layoutId: Int
get() = R.layout.activity_media_player
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
hideActionBar()
initView()
initPlayer()
}
private fun initView() {
val surfaceView = getView<SurfaceView>(R.id.surface_media)
surfaceHolder = surfaceView.holder
surfaceHolder!!.addCallback(this)
btnSelectFile = getView(R.id.btn_select_file)
initViewsWithClick(R.id.btn_select_file)
}
private fun initPlayer() {
mediaPlayer = MediaPlayer()
}
override fun surfaceCreated(holder: SurfaceHolder) {
surfaceCreated = true
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
Log.i(TAG, "surfaceChanged")
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
Log.i(TAG, "surfaceDestroyed")
}
override fun onDestroy() {
super.onDestroy()
if (mediaPlayer != null) {
mediaPlayer!!.release()
mediaPlayer = null
}
}
private fun startPlay(filePath: String) {
Thread(Runnable {
val result = mediaPlayer!!.setup(filePath, surfaceHolder!!.surface)
if (result < 0) {
Log.e(TAG, "mediaPlayer setup error!")
return@Runnable
}
mediaPlayer!!.play()
}).start()
}
override fun onSelectedFile(filePath: String) {
if (!FileUtil.checkFileExist(filePath)) {
return
}
if (surfaceCreated) {
btnSelectFile!!.visibility = View.GONE
startPlay(filePath)
}
}
override fun onViewClick(view: View) {
if (view.id == R.id.btn_select_file) {
selectFile()
}
}
companion object {
private val TAG = MediaPlayerActivity::class.java.simpleName
}
}

@ -1,39 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:id="@+id/surface_media"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<Button
android:id="@+id/btn_play_slow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentStart="true"
android:layout_margin="16dp"
android:text="@string/video_slow"
android:visibility="gone"/>
<Button
android:id="@+id/btn_play_fast"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
android:layout_margin="16dp"
android:text="@string/video_fast"
android:visibility="gone"/>
<Button
android:id="@+id/btn_select_file"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="16dp"
android:text="@string/select_file" />
</RelativeLayout>
Loading…
Cancel
Save