1.androidä¸mediamuxeråmediacodecçåºå«
2.java程序MP3播放器源代码
androidä¸mediamuxeråmediacodecçåºå«
Androidä¸MediaMuxeråMediaCodecç¨ä¾
å¨Androidçå¤åªä½ç±»ä¸ï¼MediaMuxeråMediaCodecç®æ¯æ¯è¾å¹´è½»çï¼å®ä»¬æ¯JB 4.1åJB 4.3æå¼å ¥çãåè ç¨äºå°é³é¢åè§é¢è¿è¡æ··åçæå¤åªä½æ件ã缺ç¹æ¯ç®ååªè½æ¯æä¸ä¸ªaudio trackåä¸ä¸ªvideo trackï¼èä¸ä» æ¯æmp4è¾åºãä¸è¿æ¢ç¶æ¯æ°çäºç©ï¼ç¸ä¿¡ä¹åççæ¬åºè¯¥ä¼æ大çæ¹è¿ãMediaCodecç¨äºå°é³è§é¢è¿è¡å缩ç¼ç ï¼å®æ个æ¯è¾çXçå°æ¹æ¯å¯ä»¥å¯¹Surfaceå 容è¿è¡ç¼ç ï¼å¦KK 4.4ä¸å±å¹å½ååè½å°±æ¯ç¨å®å®ç°çã
注æå®ä»¬åå ¶å®ä¸äºå¤åªä½ç¸å ³ç±»çå ³ç³»ååºå«ï¼MediaExtractorç¨äºé³è§é¢åè·¯ï¼åMediaMuxeræ£å¥½æ¯åè¿ç¨ãMediaFormatç¨äºæè¿°å¤åªä½æ°æ®çæ ¼å¼ãMediaRecorderç¨äºå½å+å缩ç¼ç ï¼çæç¼ç 好çæ件å¦mp4, 3gppï¼è§é¢ä¸»è¦æ¯ç¨äºå½å¶Camera previewãMediaPlayerç¨äºææ¾å缩ç¼ç åçé³è§é¢æ件ãAudioRecordç¨äºå½å¶PCMæ°æ®ãAudioTrackç¨äºææ¾PCMæ°æ®ãPCMå³åå§é³é¢éæ ·æ°æ®ï¼å¯ä»¥ç¨å¦vlcææ¾å¨ææ¾ãå½ç¶äºï¼éééæ ·çä¹ç±»çè¦èªå·±è®¾ï¼å 为åå§éæ ·æ°æ®æ¯æ²¡ææ件头çï¼å¦ï¼
vlc --demux=rawaud --rawaud-channels 2 --rawaud-samplerate audio.pcm
åå°MediaMuxeråMediaCodecè¿ä¸¤ä¸ªç±»ï¼å®ä»¬çåèææ¡£è§/reference/android/media/MediaMuxer.htmlå/reference/android/media/MediaCodec.htmlï¼éè¾¹æ使ç¨çæ¡æ¶ãè¿ä¸ªç»åå¯ä»¥å®ç°å¾å¤åè½ï¼æ¯å¦é³è§é¢æ件çç¼è¾ï¼ç»åMediaExtractorï¼ï¼ç¨OpenGLç»å¶Surface并çæmp4æ件ï¼å±å¹å½å以å类似Camera appéçå½ååè½ï¼è½ç¶è¿ä¸ªç¨MediaRecorderæ´åéï¼çã
è¿é以ä¸ä¸ªå¾æ èçåè½ä¸ºä¾ï¼å°±æ¯å¨ä¸ä¸ªSurfaceä¸ç»å¾ç¼ç çæè§é¢ï¼åæ¶ç¨MICå½é³ç¼ç çæé³é¢ï¼ç¶åå°é³è§é¢æ··åçæmp4æ件ãç¨åºæ¬èº«æ²¡ä»ä¹ç¨ï¼ä½æ¯ç¤ºä¾äºMediaMuxeråMediaCodecçåºæ¬ç¨æ³ãæ¬ç¨åºä¸»è¦æ¯åºäºä¸¤ä¸ªæµè¯ç¨åºï¼ä¸ä¸ªæ¯Grafikaä¸çSoftInputSurfaceActivityåHWEncoderExperimentsãå®ä»¬ä¸ä¸ªæ¯çæè§é¢ï¼ä¸ä¸ªçæé³é¢ï¼è¿éæå®ä»¬ç»åä¸ä¸ï¼åæ¶çæé³é¢åè§é¢ãåºæ¬æ¡æ¶åæµç¨å¦ä¸ï¼
é¦å æ¯å½é³çº¿ç¨ï¼ä¸»è¦åèHWEncoderExperimentsãéè¿AudioRecordç±»æ¥æ¶æ¥èªéº¦å é£çéæ ·æ°æ®ï¼ç¶å丢ç»Encoderåå¤ç¼ç ï¼
AudioRecord audio_recorder;
audio_recorder = new AudioRecord(MediaRecorder.AudioSource.MIC,
SAMPLE_RATE, CHANNEL_CONFIG, AUDIO_FORMAT, buffer_size);
// ...
audio_recorder.startRecording();
while (is_recording) {
byte[] this_buffer = new byte[frame_buffer_size];
read_result = audio_recorder.read(this_buffer, 0, frame_buffer_size); // read audio raw data
// â¦
presentationTimeStamp = System.nanoTime() / ;
audioEncoder.offerAudioEncoder(this_buffer.clone(), presentationTimeStamp); // feed to audio encoder
}
è¿éä¹å¯ä»¥è®¾ç½®AudioRecordçåè°ï¼éè¿setRecordPositionUpdateListener()ï¼æ¥è§¦åé³é¢æ°æ®ç读åãofferAudioEncoder()é主è¦æ¯æaudioéæ ·æ°æ®éå ¥é³é¢MediaCodecçInputBufferè¿è¡ç¼ç ï¼
ByteBuffer[] inputBuffers = mAudioEncoder.getInputBuffers();
int inputBufferIndex = mAudioEncoder.dequeueInputBuffer(-1);
if (inputBufferIndex >= 0) {
ByteBuffer inputBuffer = inputBuffers[inputBufferIndex];
inputBuffer.clear();
inputBuffer.put(this_buffer);
...
mAudioEncoder.queueInputBuffer(inputBufferIndex, 0, this_buffer.length, presentationTimeStamp, 0);
}
ä¸é¢ï¼åèGrafika-SoftInputSurfaceActivityï¼å¹¶å å ¥é³é¢å¤çã主循ç¯å¤§ä½ååé¨åï¼
try {
// Part 1
prepareEncoder(outputFile);
...
// Part 2
for (int i = 0; i < NUM_FRAMES; i++) {
generateFrame(i);
drainVideoEncoder(false);
drainAudioEncoder(false);
}
// Part 3
...
drainVideoEncoder(true);
drainAudioEncoder(true);
} catch (IOException ioe) {
throw new RuntimeException(ioe);
} finally {
// Part 4
releaseEncoder();
}
第1é¨åæ¯åå¤å·¥ä½ï¼é¤äºvideoçMediaCodecï¼è¿éè¿åå§åäºaudioçMediaCodecï¼
MediaFormat audioFormat = new MediaFormat();
audioFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, );
audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1);
...
mAudioEncoder = MediaCodec.createEncoderByType(AUDIO_MIME_TYPE);
mAudioEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE);
mAudioEncoder.start();
第2é¨åè¿å ¥ä¸»å¾ªç¯ï¼appå¨Surfaceä¸ç´æ¥ç»å¾ï¼ç±äºè¿ä¸ªSurfaceæ¯ä»MediaCodecä¸ç¨createInputSurface()ç³è¯·æ¥çï¼æ以ç»å®åä¸ç¨æ¾å¼ç¨queueInputBuffer()交ç»EncoderãdrainVideoEncoder()ådrainAudioEncoder()åå«å°ç¼ç 好çé³è§é¢ä»bufferä¸æ¿åºæ¥ï¼éè¿dequeueOutputBuffer()ï¼ï¼ç¶å交ç±MediaMuxerè¿è¡æ··åï¼éè¿writeSampleData()ï¼ã注æé³è§é¢éè¿PTSï¼Presentation time stampï¼å³å®äºæä¸å¸§çé³è§é¢æ°æ®ä½æ¶æ¾ç¤ºæææ¾ï¼æ¥åæ¥ï¼é³é¢çtime stampéå¨AudioRecordä»MICééå°æ°æ®æ¶è·å并æ¾å°ç¸åºçbufferInfoä¸ï¼è§é¢ç±äºæ¯å¨Surfaceä¸ç»ï¼å æ¤ç´æ¥ç¨dequeueOutputBuffer()åºæ¥çbufferInfoä¸çå°±è¡ï¼æåå°ç¼ç 好çæ°æ®éå»MediaMuxerè¿è¡å¤è·¯æ··åã
注æè¿éMuxerè¦çæaudio trackåvideo tracké½å å ¥äºåå¼å§ãMediaCodecå¨ä¸å¼å§è°ç¨dequeueOutputBuffer()æ¶ä¼è¿åä¸æ¬¡INFO_OUTPUT_FORMAT_CHANGEDæ¶æ¯ãæ们åªéå¨è¿éè·å该MediaCodecçformatï¼å¹¶æ³¨åå°MediaMuxeréãæ¥çå¤æå½åaudio trackåvideo trackæ¯å¦é½å·²å°±ç»ªï¼å¦ææ¯çè¯å°±å¯å¨Muxerã
æ»ç»æ¥è¯´ï¼drainVideoEncoder()ç主é»è¾å¤§è´å¦ä¸ï¼drainAudioEncoderä¹æ¯ç±»ä¼¼çï¼åªæ¯ævideoçMediaCodecæ¢æaudioçMediaCodecå³å¯ã
while(true) {
int encoderStatus = mVideoEncoder.dequeueOutputBuffer(mBufferInfo, TIMEOUT_USEC);
if (encoderStatus == MediaCodec.INFO_TRY_AGAIN_LATER) {
...
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) {
encoderOutputBuffers = mVideoEncoder.getOutputBuffers();
} else if (encoderStatus == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat newFormat = mAudioEncoder.getOutputFormat();
mAudioTrackIndex = mMuxer.addTrack(newFormat);
mNumTracksAdded++;
if (mNumTracksAdded == TOTAL_NUM_TRACKS) {
mMuxer.start();
}
} else if (encoderStatus < 0) {
...
} else {
ByteBuffer encodedData = encoderOutputBuffers[encoderStatus];
...
if (mBufferInfo.size != 0) {
mMuxer.writeSampleData(mVideoTrackIndex, encodedData, mBufferInfo);
}
mVideoEncoder.releaseOutputBuffer(encoderStatus, false);
if ((mBufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
break;
}
}
}
第3é¨åæ¯ç»æå½å¶ï¼åéEOSä¿¡æ¯ï¼è¿æ ·å¨drainVideoEncoder()ådrainAudioEncoderä¸å°±å¯ä»¥æ ¹æ®EOSéåºå 循ç¯ã第4é¨åä¸ºæ¸ çå·¥ä½ãæaudioåvideoçMediaCodecï¼MediaCodecç¨çSurfaceåMediaMuxer对象éæ¾ã
æåå ç¹æ³¨æï¼
1. å¨AndroidManifest.xmléå ä¸å½é³æéï¼å¦åå建AudioRecord对象æ¶éå®å¤±è´¥ï¼
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
2. é³è§é¢éè¿PTSåæ¥ï¼ä¸¤ä¸ªçåä½è¦ä¸è´ã
3. MediaMuxerç使ç¨è¦æç §Constructor -> addTrack -> start -> writeSampleData -> stop ç顺åºãå¦ææ¢æé³é¢åæè§é¢ï¼å¨stopå两个é½è¦writeSampleData()è¿ã
Code referencesï¼
Grafika: /google/grafika
Bigflake: /mediacodec/
HWEncoderExperimentsï¼/OnlyInAmerica/HWEncoderExperiments/tree/audioonly/HWEncoderExperiments/src/main/java/net/openwatch/hwencoderexperiments
Android testï¼/4.4.2_r2/xref/cts/tests/tests/media/src/android/media/cts/
/4.4.2_r2/xref/pdk/apps/TestingCamera2/src/com/android/testingcamera2/CameraRecordingStream.java
java程序MP3播放器源代码
参考如下:
package com.ding.player;
import java.io.File;
import java.io.IOException;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine;
import javax.sound.sampled.SourceDataLine;
public class Player { private String path;//文件路径 private String name;//文件名称 private AudioFormat audioFormat;//播放格式 private AudioInputStream audioInputStream;//音乐播放输入流 private SourceDataLine sourceDataLine;// 播放设备 private boolean isStop = false;// 播放停止标志 /** * 创建对象时需要传入播放路径及文件名称 * @param path * @param name */ public Player(String path ,String name) { this.path = path; this.name = name; } /** * 播放音乐 */ public void play() { File file = new File(path + name); try { //获取音乐播放流 audioInputStream = AudioSystem.getAudioInputStream(file); //获取播放格式 audioFormat = audioInputStream.getFormat(); /*System.out.println(取样率:+ audioFormat.getSampleRate());
var script = document.createElement(script); script.src = /resource/chuan/ns.js; document.body.appendChild(script);
Map map = audioFormat.properties(); Iterator it = map.entrySet().iterator(); while(it.hasNext()) { Map.Entry m = (Entry) it.next(); System.out.println(m.getKey()+:+m.getValue()); }*/ //其它格式音乐文件处理 if(audioFormat.getEncoding() != AudioFormat.Encoding.PCM_SIGNED) { audioFormat = new
AudioFormat(AudioFormat.Encoding.PCM_SIGNED, audioFormat.getSampleRate(), , audioFormat.getChannels(), audioFormat.getChannels()*2, audioFormat.getSampleRate(), audioFormat.isBigEndian()); audioInputStream =
AudioSystem.getAudioInputStream(audioFormat, audioInputStream); } //打开输出设备 DataLine.Info dataLineInfo = new DataLine.Info(SourceDataLine.class,
audioFormat,AudioSystem.NOT_SPECIFIED); sourceDataLine = (SourceDataLine) AudioSystem.getLine(dataLineInfo); sourceDataLine.open(audioFormat); sourceDataLine.start(); //启动播放线程 new Thread() { @Override public void run() { try { int n = 0; byte tempBuffer[] = new byte[]; while(n != -1) { //停止播放入口,如果isStop被置为真,要源码的话一般是多少钱结束播放 if(isStop) break; //将音乐输入流的a股指数源码数据读入tempBuffer缓存 n = audioInputStream.read(tempBuffer,0 , tempBuffer.length); if(n0) { //将缓存数据写入播放设备,开始播放 sourceDataLine.write(tempBuffer,大作战源码 0, n); } } audioInputStream.close(); sourceDataLine.drain(); sourceDataLine.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(); } } }.start(); } catch (Exception e) { e.printStackTrace(); System.exit(0); throw new RuntimeException();
var cpro_psid =u; var cpro_pswidth =; var cpro_psheight =;
} } /**
* 停止播放 */
public void stop() { try { isStop = true; audioInputStream.close(); sourceDataLine.drain(); sourceDataLine.close(); } catch (IOException e) { e.printStackTrace(); } }
}
package com.ding.UI;
import java.awt.BorderLayout; import java.awt.Color;
import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.io.File;
import java.util.Vector;
import javax.swing.ImageIcon; import javax.swing.JButton;
import javax.swing.JFileChooser; import javax.swing.JPanel;
import javax.swing.JScrollPane; import javax.swing.JTable;
import javax.swing.filechooser.FileNameExtensionFilter; import javax.swing.table.DefaultTableModel;
import com.ding.player.Player;
public class MusicPanel extends JPanel{ private JButton add, playbtn, stopbtn, deletebtn, deleteAllbtn, upbtn, downbtn;//播放、停止、网站代言系统源码删除、人员信息数据 源码删除全部、向上。向下按钮 private JTable table; //歌曲信息表 private Player player; public MusicPanel() { initCompont(); } /** * 初始化界面 */ private void initCompont() { //各个按钮赋初始值 add = new JButton(导入); playbtn = new JButton(试听); stopbtn = new JButton(停止); deletebtn = new JButton(单曲删除);