1. 在android 平台實現硬解的大俠們,你們是怎麼實現硬解碼的
1、視頻尺寸
一般都能支持176X144/352X288這種尺寸,但是大一些的,640X480就有很多機子不行了,至於為什麼,我也不知道。當然,這個尺寸必須和攝像頭預覽的尺寸一致,預覽的尺寸可以枚舉一下。
2、顏色空間
根據ANdroid SDK文檔,確保所有硬體平台都支持的顏色,在攝像頭預覽輸出是YUV12,在編碼器輸入是COLOR_FormatYUV420Planar,也就是前面代碼中設置的那樣。 不過,文檔終究是文檔,否則安卓就不是安卓。
在有的平台上,這兩個顏色格式是一樣的,攝像頭的輸出可以直接作為編碼器的輸入。也有的平台,兩個是不一樣的,前者就是YUV12,後者等於I420,需要把前者的UV分量顛倒一下。
byte[] i420bytes = null;
private byte[] swapYV12toI420(byte[] yv12bytes, int width, int height) {
if (i420bytes == null)
i420bytes = new byte[yv12bytes.length];
for (int i = 0; i < width*height; i++)
i420bytes[i] = yv12bytes[i];
for (int i = width*height; i < width*height + (width/2*height/2); i++)
i420bytes[i] = yv12bytes[i + (width/2*height/2)];
for (int i = width*height + (width/2*height/2); i < width*height + 2*(width/2*height/2); i++)
i420bytes[i] = yv12bytes[i - (width/2*height/2)];
return i420bytes;
}
3、輸入輸出緩沖區的格式
SDK里並沒有規定格式,但是,這種情況H264的格式基本上就是附錄B。但是,也有比較有特色的,它就是不帶那個StartCode,就是那個0x000001,搞得把他編碼器編出來的東西送給他的解碼器。
ByteBuffer outputBuffer = outputBuffers[outputBufferIndex];
byte[] outData = new byte[bufferInfo.size + 3];
outputBuffer.get(outData, 3, bufferInfo.size);
if (frameListener != null) {
if ((outData[3]==0 && outData[4]==0 && outData[5]==1)
|| (outData[3]==0 && outData[4]==0 && outData[5]==0 && outData[6]==1))
{
frameListener.onFrame(outData, 3, outData.length-3, bufferInfo.flags);
}
else
{
outData[0] = 0;
outData[1] = 0;
outData[2] = 1;
frameListener.onFrame(outData, 0, outData.length, bufferInfo.flags);
}
}
2. android 中的 ffmpeg 是否添加了 rockchip 的硬體編解碼功能
涉及到硬編硬解絕對就是跟平台相關了,必須要用到相應平台的編解碼庫,還不如在自己寫個庫,自己調用,何必集成到ffmpeg中呢
3. 安卓工程怎麼利用第三方庫,就是自己用C++編寫的編碼解碼程序,對圖片進行編碼解碼
你可以嘗試將構造函數和析構函數一起導出,並且,將編譯DLL文件時生成的LIB文件添加到調用DLL的項目中.
如果還不行,請將定義DLL的頭文件貼出來分析.
------------------------------------------------------------------
補充:
MFC擴展DLL只能由MFC的應用程序調用,請問你調用DLL的程序是什麼類型?
4. android使用mediacodec進行編解碼 常用嗎
應該還是比較常用的。示例如下:
java">privatefinalStringTAG="MediaCodeSample";
/**用來解碼*/
privateMediaCodecmMediaCodec;
/**用來讀取音頻文件*/
;
privateMediaFormatformat;
privateStringmime=null;
privateintsampleRate=0,channels=0,bitrate=0;
privatelongpresentationTimeUs=0,ration=0;
publicvoiddecode(Stringurl)
{
extractor=newMediaExtractor();
//根據路徑獲取源文件
try
{
extractor.setDataSource(url);
}catch(Exceptione)
{
Log.e(TAG,"設置文件路徑錯誤"+e.getMessage());
}
try
{
//音頻文件信息
format=extractor.getTrackFormat(0);
mime=format.getString(MediaFormat.KEY_MIME);
sampleRate=format.getInteger(MediaFormat.KEY_SAMPLE_RATE);
//聲道個數:單聲道或雙聲道
channels=format.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
//ifrationis0,
ration=format.getLong(MediaFormat.KEY_DURATION);
//System.out.println("歌曲總時間秒:"+ration/1000000);
bitrate=format.getInteger(MediaFormat.KEY_BIT_RATE);
}catch(Exceptione)
{
Log.e(TAG,"音頻文件信息讀取出錯:"+e.getMessage());
//不要退出,下面進行判斷
}
Log.d(TAG,"Trackinfo:mime:"+mime+"采樣率sampleRate:"+sampleRate+"channels:"+channels+"bitrate:"
+bitrate+"ration:"+ration);
//檢查是否為音頻文件
if(format==null||!mime.startsWith("audio/"))
{
Log.e(TAG,"不是音頻文件end!");
return;
}
//實例化一個指定類型的解碼器,提供數據輸出
//
mMediaCodec=MediaCodec.createDecoderByType(mime);
if(mMediaCodec==null)
{
Log.e(TAG,"創建解碼器失敗!");
return;
}
mMediaCodec.configure(format,null,null,0);
mMediaCodec.start();
//用來存放目標文件的數據
ByteBuffer[]inputBuffers=mMediaCodec.getInputBuffers();
//解碼後的數據
ByteBuffer[]outputBuffers=mMediaCodec.getOutputBuffers();
//設置聲道類型:AudioFormat.CHANNEL_OUT_MONO單聲道,AudioFormat.CHANNEL_OUT_STEREO雙聲道
intchannelConfiguration=channels==1?AudioFormat.CHANNEL_OUT_MONO:AudioFormat.CHANNEL_OUT_STEREO;
Log.i(TAG,"channelConfiguration="+channelConfiguration);
extractor.selectTrack(0);
//==========開始解碼=============
booleansawInputEOS=false;
booleansawOutputEOS=false;
finallongkTimeOutUs=10;
MediaCodec.BufferInfoinfo=newMediaCodec.BufferInfo();
while(!sawOutputEOS)
{
try
{
if(!sawInputEOS)
{
intinputBufIndex=mMediaCodec.dequeueInputBuffer(kTimeOutUs);
if(inputBufIndex>=0)
{
ByteBufferdstBuf=inputBuffers[inputBufIndex];
intsampleSize=extractor.readSampleData(dstBuf,0);
if(sampleSize<0)
{
Log.d(TAG,"sawinputEOS.Stoppingplayback");
sawInputEOS=true;
sampleSize=0;
}else
{
presentationTimeUs=extractor.getSampleTime();
}
mMediaCodec.queueInputBuffer(inputBufIndex,0,sampleSize,presentationTimeUs,
sawInputEOS?MediaCodec.BUFFER_FLAG_END_OF_STREAM:0);
if(!sawInputEOS)
{
extractor.advance();
}
}else
{
Log.e(TAG,"inputBufIndex"+inputBufIndex);
}
}//!sawInputEOS
//
intres=mMediaCodec.dequeueOutputBuffer(info,kTimeOutUs);
if(res>=0)
{
intoutputBufIndex=res;
ByteBufferbuf=outputBuffers[outputBufIndex];
finalbyte[]chunk=newbyte[info.size];
buf.get(chunk);
buf.clear();
if(chunk.length>0)
{
//chunk解碼後的音頻流
//TODO:處理...
}
mMediaCodec.releaseOutputBuffer(outputBufIndex,false);
if((info.flags&MediaCodec.BUFFER_FLAG_END_OF_STREAM)!=0)
{
Log.d(TAG,"sawoutputEOS.");
sawOutputEOS=true;
}
}elseif(res==MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED)
{
outputBuffers=mMediaCodec.getOutputBuffers();
Log.w(TAG,"[AudioDecoder]outputbuffershavechanged.");
}elseif(res==MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
MediaFormatoformat=mMediaCodec.getOutputFormat();
Log.w(TAG,"[AudioDecoder]outputformathaschangedto"+oformat);
}else
{
Log.w(TAG,"[AudioDecoder]dequeueOutputBufferreturned"+res);
}
}catch(RuntimeExceptione)
{
Log.e(TAG,"[decodeMP3]error:"+e.getMessage());
}
}
//=================================================================================
if(mMediaCodec!=null)
{
mMediaCodec.stop();
mMediaCodec.release();
mMediaCodec=null;
}
if(extractor!=null)
{
extractor.release();
extractor=null;
}
//clearsourceandtheotherglobals
ration=0;
mime=null;
sampleRate=0;
channels=0;
bitrate=0;
presentationTimeUs=0;
ration=0;
}
5. 怎樣用AACLib V1.0在Android上音頻編碼解碼
這幾天在 android上的音頻項目,順便把用到的aac編解碼庫封裝了一下,有需要的可以從上面下載。當然我是沒有本事自己寫編解碼器的,還是用FFmpeg + FDK_aac來做。下面介紹一下其java介面的使用。java庫見libaac.jar文件,把libaac.jar加到 libs目錄下,把libaac.so加到 libs/armeabi目錄即可使用。
AAC編碼:
(1) 創建一個Encoder對象作為成員變數
aac.Encoder encoder;
(2) 初始化它
encoder = new aac.Encoder();
if(! encoder.open(11025, 1))
{
Log.d("mylog", "failed to open encoder !\n");
encoder = null;
}
這里要指定輸入音頻源(PCM格式)的sampe_rate和channel個數,如果為CHANNEL_OUT_MONO,則channel=1,否則為2。 sample_rate一般設置為11025,因為手機性能有限,設置太高的話也處理不過來,而且處理人聲的話11025也是足夠了。
(3) 編碼
把接收到PCM數據交給encoder來處理即可,要求輸入源為ENCODING_PCM_16BIT,即每個sample是16BIT的。這個encoder對象內有2個緩沖區:inbuf, outbuf。顯然,在編碼時,inbuf就是用於存儲接收到的PCM數據,outbuf就是存編碼後得到的數據。
int out_size = encoder.encode(in_size);
其返回值out_size,表示在outbuf里的有效數據長度。此時可以把outbuf里的aac數據通過網路發送或其他用途。
其中,用戶需要知道encoder每次處理多長的數據,即一個frame的大小。對於單聲道MONO來說,每次應該輸入2048byte的數據。對於雙聲道STEREO來說,應該輸入4096byte的數據。下面這一行可以根據聲道數來計算輸入的frame的大小:
int in_size = aac.Encoder.frameSize(1);
AAC解碼:
(1) 創建一個Decoder對象作為成員變數
aac.Decoder decoder;
(2) 初始化
decoder = new aac.Decoder();
if( ! decoder.open())
{
Log.d("mylog", "failed to open decoder !\n");
decoder = null;
}
(3) 解碼
Decoder對象也有inbuf和outbuf,把待解碼的aac frame放到inbuf里
int pcm_size = decoder.decode(aac_size);
解得到數據在outbuf里,其有效長度為上述函數的返回值pcm_size,此時可以把outbuf里的PCM數據取出來播放或其他用途。
6. 如何在Android用FFmpeg解碼圖像
創建一個VideoPicture結構體用來保存解碼出來的圖像。
LOCAL_PATH := $(call my-dir)
###########################
#
# SDL shared library
#
###########################
include $(CLEAR_VARS)
LOCAL_MODULE := SDL2
LOCAL_C_INCLUDES := $(LOCAL_PATH)/include
LOCAL_EXPORT_C_INCLUDES := $(LOCAL_C_INCLUDES)
LOCAL_SRC_FILES := \
$(subst $(LOCAL_PATH)/,, \
$(wildcard $(LOCAL_PATH)/src/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/audio/mmy/*.c) \
$(LOCAL_PATH)/src/atomic/SDL_atomic.c \
$(LOCAL_PATH)/src/atomic/SDL_spinlock.c.arm \
$(wildcard $(LOCAL_PATH)/src/core/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/cpuinfo/*.c) \
$(wildcard $(LOCAL_PATH)/src/dynapi/*.c) \
$(wildcard $(LOCAL_PATH)/src/events/*.c) \
$(wildcard $(LOCAL_PATH)/src/file/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/*.c) \
$(wildcard $(LOCAL_PATH)/src/haptic/mmy/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/*.c) \
$(wildcard $(LOCAL_PATH)/src/joystick/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/loadso/dlopen/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/*.c) \
$(wildcard $(LOCAL_PATH)/src/power/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/filesystem/mmy/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*.c) \
$(wildcard $(LOCAL_PATH)/src/render/*/*.c) \
$(wildcard $(LOCAL_PATH)/src/stdlib/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/*.c) \
$(wildcard $(LOCAL_PATH)/src/thread/pthread/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/*.c) \
$(wildcard $(LOCAL_PATH)/src/timer/unix/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/*.c) \
$(wildcard $(LOCAL_PATH)/src/video/android/*.c) \
$(wildcard $(LOCAL_PATH)/src/test/*.c))
LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES
LOCAL_LDLIBS := -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
include $(BUILD_SHARED_LIBRARY)
###########################
#
# SDL static library
#
###########################
#LOCAL_MODULE := SDL2_static
#LOCAL_MODULE_FILENAME := libSDL2
#LOCAL_SRC_FILES += $(LOCAL_PATH)/src/main/android/SDL_android_main.c
#LOCAL_LDLIBS :=
#LOCAL_EXPORT_LDLIBS := -Wl,--undefined=Java_org_libsdl_app_SDLActivity_nativeInit -ldl -lGLESv1_CM -lGLESv2 -llog -landroid
#include $(BUILD_STATIC_LIBRARY)
二、參考[原]如何在Android用FFmpeg解碼圖像, 在工程中新建一個ffmpeg文件夾,將與ffmpeg相關的頭文件include進來。ffmpeg文件夾下的Android.mk內容:
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE := ffmpeg
LOCAL_SRC_FILES := /path/to/build/ffmpeg/libffmpeg.so
include $(PREBUILT_SHARED_LIBRARY)
三、新建player文件夾,用來編寫解碼與顯示文件。player.c文件內容:
/*
* SDL_Lesson.c
*
* Created on: Aug 12, 2014
* Author: clarck
*/
#include <jni.h>
#include <android/native_window_jni.h>
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_events.h"
#include "../include/logger.h"
#include "../ffmpeg/include/libavcodec/avcodec.h"
#include "../ffmpeg/include/libavformat/avformat.h"
#include "../ffmpeg/include/libavutil/pixfmt.h"
#include "../ffmpeg/include/libswscale/swscale.h"
int main(int argc, char *argv[]) {
char *file_path = argv[1];
LOGI("file_path:%s", file_path);
AVFormatContext *pFormatCtx;
AVCodecContext *pCodecCtx;
AVCodec *pCodec;
AVFrame *pFrame, *pFrameYUV;
AVPacket *packet;
uint8_t *out_buffer;
SDL_Texture *bmp = NULL;
SDL_Window *screen = NULL;
SDL_Rect rect;
SDL_Event event;
static struct SwsContext *img_convert_ctx;
int videoStream, i, numBytes;
int ret, got_picture;
av_register_all();
pFormatCtx = avformat_alloc_context();
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) {
LOGE("Could not initialize SDL - %s. \n", SDL_GetError());
exit(1);
}
if (avformat_open_input(&pFormatCtx, file_path, NULL, NULL) != 0) {
LOGE("can't open the file. \n");
return -1;
}
if (avformat_find_stream_info(pFormatCtx, NULL) < 0) {
LOGE("Could't find stream infomation.\n");
return -1;
}
videoStream = 1;
for (i = 0; i < pFormatCtx->nb_streams; i++) {
if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
videoStream = i;
}
}
LOGI("videoStream:%d", videoStream);
if (videoStream == -1) {
LOGE("Didn't find a video stream.\n");
return -1;
}
pCodecCtx = pFormatCtx->streams[videoStream]->codec;
pCodec = avcodec_find_decoder(pCodecCtx->codec_id);
if (pCodec == NULL) {
LOGE("Codec not found.\n");
return -1;
}
if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0) {
LOGE("Could not open codec.\n");
return -1;
}
pFrame = av_frame_alloc();
pFrameYUV = av_frame_alloc();
//---------------------------init sdl---------------------------//
screen = SDL_CreateWindow("My Player Window", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, pCodecCtx->width, pCodecCtx->height,
SDL_WINDOW_FULLSCREEN | SDL_WINDOW_OPENGL);
SDL_Renderer *renderer = SDL_CreateRenderer(screen, -1, 0);
bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12,
SDL_TEXTUREACCESS_STREAMING, pCodecCtx->width, pCodecCtx->height);
//-------------------------------------------------------------//
img_convert_ctx = sws_getContext(pCodecCtx->width, pCodecCtx->height,
pCodecCtx->pix_fmt, pCodecCtx->width, pCodecCtx->height,
AV_PIX_FMT_YUV420P, SWS_BICUBIC, NULL, NULL, NULL);
numBytes = avpicture_get_size(AV_PIX_FMT_YUV420P, pCodecCtx->width,
pCodecCtx->height);
out_buffer = (uint8_t *) av_malloc(numBytes * sizeof(uint8_t));
avpicture_fill((AVPicture *) pFrameYUV, out_buffer, AV_PIX_FMT_YUV420P,
pCodecCtx->width, pCodecCtx->height);
rect.x = 0;
rect.y = 0;
rect.w = pCodecCtx->width;
rect.h = pCodecCtx->height;
int y_size = pCodecCtx->width * pCodecCtx->height;
packet = (AVPacket *) malloc(sizeof(AVPacket));
av_new_packet(packet, y_size);
av_mp_format(pFormatCtx, 0, file_path, 0);
while (av_read_frame(pFormatCtx, packet) >= 0) {
if (packet->stream_index == videoStream) {
ret = avcodec_decode_video2(pCodecCtx, pFrame, &got_picture,
packet);
if (ret < 0) {
LOGE("decode error.\n");
return -1;
}
LOGI("got_picture:%d", got_picture);
if (got_picture) {
sws_scale(img_convert_ctx,
(uint8_t const * const *) pFrame->data,
pFrame->linesize, 0, pCodecCtx->height, pFrameYUV->data,
pFrameYUV->linesize);
////iPitch 計算yuv一行數據占的位元組數
SDL_UpdateTexture(bmp, &rect, pFrameYUV->data[0], pFrameYUV->linesize[0]);
SDL_RenderClear(renderer);
SDL_RenderCopy(renderer, bmp, &rect, &rect);
SDL_RenderPresent(renderer);
}
SDL_Delay(50);
}
av_free_packet(packet);
SDL_PollEvent(&event);
switch (event.type) {
case SDL_QUIT:
SDL_Quit();
exit(0);
break;
default:
break;
}
7. 如何在 android 設備上使用 pjsip G.729 編解碼的功能
第一步是生成 pjsip 為 Android (步驟為 Ubuntu linux) 的源代碼:
1.設置 ANDROID_NDK_ROOT 環境變數設置為您 NDK 根文件夾。
2.轉到 pjsip 2.x 文件夾並創建 pjlib/include/pj/config_site.h 包括 config_site_sample.h ( #include <pj/config_site_sample.h> )
3.運行./configure-android
4.運行make clean && make depend && make
之後這些步驟,將有幾個靜態庫中的幾個文件夾。建議將它們分組相同的文件夾 (最好在您的項目中) 中的:
mkdir <your_project_path>/pjsip_libs
find . -name *.a | xargs -I % cp % <your_project_path>/pjsip_libs/
一旦自己的所有庫,您需要將這些庫添加到您的項目 Android.mk 文件,這是由包括一個新的模塊節每個圖書館。此模塊部分應該是一樣的東西:
include $(CLEAR_VARS)
LOCAL_MODULE := pjsua-arm-unknown-linux-androideabi
LOCAL_SRC_FILES := $(MY_PJLIB_PATH)/libpjsua-arm-unknown-linux-androideabi.a
include $(PREBUILT_STATIC_LIBRARY)
,其實是一節中構建您的 JNI 項目的源代碼,所有模塊都添加到您的靜態庫的引用:
LOCAL_STATIC_LIBRARIES := pjsua-arm-unknown-linux-androideabi ...
這將包括 pjsip 的引用加入您的 JNI 庫。現在,您需要配置 pjsip UA 實例。
有一個關於 init 和開始的解釋 pjsip 的 UA (pjsua) 在 pjsip/include/pjsua-lib/pjsua.h 但要遵循的主要步驟是:
1.創建一個具有 UA 實例pjsua_create
2.創建一個工作線程與pj_thread_create
3.UA 實例的設置的默認配置:
pjsua_config cfg 樁 ;pjsua_logging_config log_cfg ;pjsua_media_config media_cfg ;
pj_cli_cfg_default(&app_config.cli_cfg.cfg) ;pjsua_logging_config_default(&log_cfg) ;pjsua_media_config_default(&media_cfg) ;
4.初始化堆棧與pjsua_init
5.啟動與堆棧pjsua_start
從這里,有充足的配置選項 (日誌、 媒體、 交通工具等)
您可以找到基本 PJSIP 教程在這里,和裡面 pjsip 的源的根路徑,有一個基本 (但不夠完整,基本的 SIP 使用情況) 在:pjsip-apps/src/samples/simple_pjsua.c
編輯:在生成時在 pjsip 應用程序的 android 項目,可以面臨一個問題,因為 pjsua app 不生成默認情況下,對一般生成 (更具體地說,pjsua: 目標不包括所有上: 在 pjsip-應用程序/生成/生成文件的目標)。若要修復這只是轉到 pjsip-應用程序/創建和運行:
使 pjsua
這將創建在正確的對象文件: pjsip-apps/build/output/pjsua-arm-unknown-linux-androideabi/ (需要構建 android 樣本時)。
一旦所有相應的對象文件,您可以在 pjsip-應用程序/src/pjsua/android 系統再次運行 ndk 生成
8. 音頻播放需要用到編解碼技術嗎 android
1、android提供的音視頻編碼只有 AMR-NB(nb是窄頻)和H.263
2、android雖然支持gif的解碼,只能用mediaplay來播放,但是效果不好
3、android不支持flv的解碼
4、AudioTrack只能播放pcm編碼的數據,MediaPlayer可以播放MP3,AAC,WAV,OGG,MIDI等
事實上,兩種本質上是沒啥區別的,MediaPlayer在播放音頻時,在framework層還是會創建AudioTrack,
把解碼後的PCM數據傳遞給AudioTrack,最後由AudioFlinger進行混音,傳遞音頻給硬體播放出來。
利用AudioTrack播放只是跳過 Mediaplayer的解碼部分而已。Mediaplayer的解碼核心部分是基於OpenCORE 來實現的,
支持通用的音視頻和圖像格式,codec使用的是OpenMAX介面來進行擴展。因此使用audiotrack播放mp3文件的話,要自己加入 一個音頻解碼器,如libmad。
否則只能播放PCM數據,如大多數WAV格式的音頻文件。
9. 如何在Android用FFmpeg+SDL2.0解碼聲音
一、創建一個VideoPicture結構體用來保存解碼出來的圖像;
二、添加數據隊列的初始化、添加以及讀取的函數;
三、audio_decode_frame():解碼音頻;
四、audio_callback(): 回調函數,向SDL緩沖區填充數據;
五、創建刷新相關的函數;
六、添加顯示函數;
七、分配顯示輸出內存空間;
八、解碼線程,將解碼器,建立音頻線,保存重要信息到數據結構中;
九、編寫Main函數用來調用解碼線程。
知識點延伸:
FFmpeg是一個開源跨的和音頻流方案,屬於自由,採用LGPL或GPL許可證(依據你選擇的組件)。它提供了錄制、轉換以及流化音的完整解決方案。它包含了非常先進的音頻/編解碼庫libavcodec,為了保證高可移植性和編解碼質量,libavcodec里很多codec都是從頭開發的。FFmpeg在Linux下開發,但它同樣也可以在其它操作系統環境中編譯運行。
SDL2.0(Simple DirectMedia Layer)是一套開放源代碼的跨多媒體開發庫,使用C語言寫成。SDL多用於開發游戲、模擬器、媒體播放器等多媒體應用領域。SDL內置了調用OpenGL的函數。SDL提供了數種控制圖像、聲音、輸出入的函數,讓開發者只要用相同或是相似的代碼就可以開發出跨多個(Linux、Windows、Mac OS X等)的應用。
10. Android簡訊編解碼形式怎麼解決
安卓簡訊怎麼導入iphone?安卓手機換蘋果怎麼轉移簡訊?安下小編有辦法,來看看吧。 一、用QQ同步助手導出安卓手機簡訊 1/,在「我的資料庫」找到簡訊,點擊 「所有對話」,然後「導出本組全部簡訊」(注意提示的解壓密碼),點擊導出。 3/s/1nt5grxB 下載工具A2I.EXE,運行界面如下。 2.點擊【選擇Android手機簡訊文件】按鈕,選擇第一步用QQ同步助手導出的簡訊CSV文件,在CSV文件預覽框中會顯示其內容。(注意:如果預覽框中現實的都是亂碼,就先用記事本打開這個CSV文件,然後保存,再使用本軟體。)然後點擊【開始轉換】按鈕,簡訊內容就會顯示在簡訊解析框中,並且轉換後的內容就保存在SMS.CSV文件中。 3.用記事本打開上一步A2I.EXE軟體產生的SMS.CSV文件,同時用記事本打開用iTools導出的iPhone簡訊CSV文件,將該文件中的簡訊復制到SMS.CSV文件中,完成簡訊內容合並(有個別簡訊可能存在亂碼,刪除)。最後另存該文件,選擇編碼為UTF-8,保存類型改為"所有文檔",保存為CSV文件。 四、將簡訊數據導入到iTunes備份文件 1.刪除原有簡訊。打開iTOOLS點擊右上角的「工具箱」,找到「iTunes備份管理」,打開第二步的備份,找到「簡訊」中的「sms.db」,雙擊打開,這時簡訊就列出來了,全選並且點擊「刪除」。 2.導入新的簡訊文件。點擊「導入」,選擇「導入CSV文件」,導入第三步產生的CSV文件。 五、恢復備份到iPhone重啟完成 點擊「同步到設備」,完成簡訊的導入(注意:在同步到設備的時候,手機不能鎖屏,要在點亮狀態,而且同步之後手機會重啟,重啟完成後就成功導入安卓的簡訊了)。