Android C++ 播放 MP3 Demo 笔记

前言

使用 Android C++ 编写 MP3 播放程序,使用的是 framework\av\media\libmedia\mediaplayer.cpp 里面的 MediaPlayer 类。实现了本地播放和在线播放两种方式。

代码

其中,如果要播放 video,则需要和屏相关,使用到 surface。如下:

	//video : need SurfaceFlinger
     if (playback && (useSurface && useVideo)) {
        composerClient = new SurfaceComposerClient;
        CHECK_EQ(composerClient->initCheck(), (status_t)OK);

        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
                ISurfaceComposer::eDisplayIdMain));
        DisplayInfo info;
        SurfaceComposerClient::getDisplayInfo(display, &info);
        ssize_t displayWidth = info.w;
        ssize_t displayHeight = info.h;

        ALOGI("display is %ld x %ld\n", displayWidth, displayHeight);

        control = composerClient->createSurface(
                String8("A Surface"),
                displayWidth,
                displayHeight,
                PIXEL_FORMAT_RGB_565,
                0);

        CHECK(control != NULL);
        CHECK(control->isValid());

        SurfaceComposerClient::openGlobalTransaction();
        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
        CHECK_EQ(control->show(), (status_t)OK);
        SurfaceComposerClient::closeGlobalTransaction();

        surface = control->getSurface();
        CHECK(surface != NULL);
    }

要等待一个音源文件播放完毕后,才退出播放程序,则需要使用到 MPlayerListener 进行监听,需要我们注册监听函数:

   sp<MPlayerListener> mListener = new MPlayerListener();
   player->setListener(mListener);	
   //....
   mSignal.wait(mLock);
//实现监听(注册监听)
class MPlayerListener : public MediaPlayerListener
{
    void notify(int msg, int ext1, int ext2, const Parcel * /*obj*/)
    {
        switch (msg) {
        case MEDIA_ERROR:
            // Always log errors.
            ALOGE("error (%d, %d)", ext1, ext2);
            //fall through
        case MEDIA_PLAYBACK_COMPLETE:
            ALOGD("play media finished, quit");
            if (player != NULL) {
                player->stop();
                player->reset();
                player->setListener(0);
                player->disconnect();
                mPlayState = PLAYER_STATE_STOP;
				if (fd != NULL) {
					close(fd);
					fd = NULL;
				}
            }
           // mSignal.signal();
            break;
        default:
            break;
        }
    }
};

音源文件有的是放在本地,有的是放置在网络上。MediaPlayer 类已经重载了方法 setDataSource,用于确定是本地播放还是网络在线播放:

//在线播放
player->setDataSource("http://oss.iot.aispeech.com/dcmp/02/BB/CiAB81uI9mOAVKcGAAqZVmc8ics229.mp3", NULL);
//本地播放
int fd = open(argv[0], O_RDONLY);
player->setDataSource(fd, 0, 0x7ffffffffffffffLL);

播放流程一般为:

  • prepare
  • start
  • stop
  • reset

完整代码如下:

/*
 * Copyright (C) 2012 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 "player"
#include <utils/Log.h>

#include "SimplePlayer.h"

#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <media/IMediaPlayerService.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/AString.h>
#include <media/stagefright/MediaDefs.h>
#include <gui/ISurfaceComposer.h>
#include <gui/SurfaceComposerClient.h>
#include <gui/Surface.h>
#include <ui/DisplayInfo.h>
#include <media/mediaplayer.h>
#include <fcntl.h>
#include <media/AudioSystem.h>

sp<MediaPlayer> player = NULL;
player_states  mPlayState = PLAYER_STATE_NONE;
int  fd = NULL;
//bool isstop = false;
//bool ispause =false;
Mutex               mLock;
Condition           mSignal;

class MPlayerListener : public MediaPlayerListener
{
    void notify(int msg, int ext1, int ext2, const Parcel * /*obj*/)
    {
        switch (msg) {
        case MEDIA_ERROR:
            // Always log errors.
            ALOGE("error (%d, %d)", ext1, ext2);
            //fall through
        case MEDIA_PLAYBACK_COMPLETE:
            ALOGD("play media finished, quit");
            if (player != NULL) {
                player->stop();
                player->reset();
                player->setListener(0);
                player->disconnect();
                mPlayState = PLAYER_STATE_STOP;
				if (fd != NULL) {
					close(fd);
					fd = NULL;
				}
            }
           // mSignal.signal();
            break;
        default:
            break;
        }
    }
};


static void usage(const char *me) {
    fprintf(stderr, "usage: %s [-a] use audio\n"
                    "\t\t[-v] use video\n"
                    "\t\t[-p] playback\n"
                    "\t\t[-S] allocate buffers from a surface\n",
                    me);

    exit(1);
}

int main(int argc, char **argv) {
    using namespace android;

    const char *me = argv[0];

    bool useAudio = false;
    bool useVideo = false;
    bool playback = false;
    bool useSurface = false;

    int res;
     while ((res = getopt(argc, argv, "havpSD")) >= 0) {
        switch (res) {
            case 'a':
            {
                useAudio = true;
                break;
            }

            case 'v':
            {
                useVideo = true;
                break;
            }

            case 'p':
            {
                playback = true;
                break;
            }

            case 'S':
            {
                useSurface = true;
                break;
            }

            case '?':
            case 'h':
            default:
            {
                usage(me);
            }
        }
    }

    argc -= optind;
    argv += optind;

    if (argc != 1) {
        usage(me);
    }

    if (!useAudio && !useVideo) {
        useAudio = useVideo = true;
    }
 

    ProcessState::self()->startThreadPool();

     sp<SurfaceComposerClient> composerClient;
    sp<SurfaceControl> control;
    sp<Surface> surface; 

	//video : need SurfaceFlinger
     if (playback && (useSurface && useVideo)) {
        composerClient = new SurfaceComposerClient;
        CHECK_EQ(composerClient->initCheck(), (status_t)OK);

        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
                ISurfaceComposer::eDisplayIdMain));
        DisplayInfo info;
        SurfaceComposerClient::getDisplayInfo(display, &info);
        ssize_t displayWidth = info.w;
        ssize_t displayHeight = info.h;

        ALOGI("display is %ld x %ld\n", displayWidth, displayHeight);

        control = composerClient->createSurface(
                String8("A Surface"),
                displayWidth,
                displayHeight,
                PIXEL_FORMAT_RGB_565,
                0);

        CHECK(control != NULL);
        CHECK(control->isValid());

        SurfaceComposerClient::openGlobalTransaction();
        CHECK_EQ(control->setLayer(INT_MAX), (status_t)OK);
        CHECK_EQ(control->show(), (status_t)OK);
        SurfaceComposerClient::closeGlobalTransaction();

        surface = control->getSurface();
        CHECK(surface != NULL);
    }
 
	//audio && video
    if (playback) {
#ifdef _PLAY_ONLINE_
		sp<MediaPlayer> player = new MediaPlayer();
        sp<MPlayerListener> mListener = new MPlayerListener();
        player->setListener(mListener);		
		player->setDataSource("http://oss.iot.aispeech.com/dcmp/02/BB/CiAB81uI9mOAVKcGAAqZVmc8ics229.mp3", NULL);
		player->setAudioStreamType(AUDIO_STREAM_MUSIC);
		ALOGI("player->prepare");
		player->prepare();
		player->start();
		player->setVolume(1.0, 1.0);
		ALOGI("player->start()");
		//sleep(60);
		//player->stop();
		//ALOGI("player->stop()");
		//player->reset();
		//ALOGI("player->reset()");
		mSignal.wait(mLock);		
#else
        int fd = open(argv[0], O_RDONLY);
        ALOGI("open path: %s", argv[0]);
        if (fd <= 0) {
            ALOGE("open file failed, fd: %d, path: %s", fd, argv[0]);
        } else {
            sp<MediaPlayer> player = new MediaPlayer();
			sp<MPlayerListener> mListener = new MPlayerListener();
			player->setListener(mListener);				
            ALOGI("player->setDataSource fd: %d", fd);
            player->setDataSource(fd, 0, 0x7ffffffffffffffLL);
            player->setAudioStreamType(AUDIO_STREAM_MUSIC);
            ALOGI("player->prepare");
            player->prepare();
            if (useSurface && useVideo) {
                player->setVideoSurfaceTexture(surface->getIGraphicBufferProducer());
            }
            player->start();
            player->setVolume(1.0, 1.0);
            ALOGI("player->start()");
            //sleep(240);
            //player->stop();
			//ALOGI("player->stop()");
            //player->reset();
			//ALOGI("player->reset()");
			mSignal.wait(mLock);			
        }
#endif
    }
 
    if (playback && (useSurface && useVideo)) {
        composerClient->dispose();
    }
 
    return 0;
}

该代码可以放置在 framework\av\cmds\stagefright\ 目录下进行编译。
可编写 Android,mk 如下:

################################################################################

include $(CLEAR_VARS)

LOCAL_SRC_FILES:=               \
        player.cpp               \

LOCAL_SHARED_LIBRARIES := \
	libstagefright liblog libutils libbinder libstagefright_foundation \
        libmedia libgui libcutils libui

LOCAL_C_INCLUDES:= \
	frameworks/av/media/libstagefright \
	$(TOP)/frameworks/native/include/media/openmax

LOCAL_CFLAGS += -Wno-multichar

LOCAL_MODULE_TAGS := optional

LOCAL_MODULE:= player

include $(BUILD_EXECUTABLE)
# include $(BUILD_SHARED_LIBRARY)

################################################################################

以上,目前在Android4.4上经过了验证。

发布了30 篇原创文章 · 获赞 24 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/q1075355798/article/details/104357424