private MediaFormat selectTrack(MediaExtractor extractor) { int trackCount = extractor.getTrackCount(); Log.d(TAG, "trackCount :" + trackCount); MediaFormat format; for (int i = 0; i < trackCount; i++) { extractor.selectTrack(i); format = extractor.getTrackFormat(i); Log.d(TAG, "Track media format :" + format.toString()); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { return format; } } return null; }
@Override public void setup() throws IOException { mExtractor.selectTrack(mTrackIndex); mEncoder = MediaCodec.createEncoderByType(mOutputFormat.getString(MediaFormat.KEY_MIME)); mEncoder.configure(mOutputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mEncoder.start(); mEncoderStarted = true; final MediaFormat inputFormat = mExtractor.getTrackFormat(mTrackIndex); mDecoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME)); mDecoder.configure(inputFormat, null, null, 0); mDecoder.start(); mDecoderStarted = true; mAudioChannel = new AudioChannel(mDecoder, mEncoder, mOutputFormat); }
/** * 获取视频信息 * * @param url * @return */ public static long getDuration(String url) { try { MediaExtractor mediaExtractor = new MediaExtractor(); mediaExtractor.setDataSource(url); int videoExt = TrackUtils.selectVideoTrack(mediaExtractor); if(videoExt == -1){ videoExt = TrackUtils.selectAudioTrack(mediaExtractor); if(videoExt == -1){ return 0; } } MediaFormat mediaFormat = mediaExtractor.getTrackFormat(videoExt); long res = mediaFormat.containsKey(MediaFormat.KEY_DURATION) ? mediaFormat.getLong(MediaFormat.KEY_DURATION) : 0;//时长 mediaExtractor.release(); return res; } catch (Exception e) { return 0; } }
@Override public Point open(SurfaceTexture surface) { try { if(!extractMedia()){ return new Point(0,0); } mFrameSem=new Semaphore(0); mDecodeSem=new Semaphore(1); videoProvideEndFlag=false; isUserWantToStop=false; mAudioEncodeTrack=mStore.addTrack(mExtractor.getTrackFormat(mAudioDecodeTrack)); MediaFormat format=mExtractor.getTrackFormat(mVideoDecodeTrack); mVideoDecoder = MediaCodec.createDecoderByType(format.getString(MediaFormat.KEY_MIME)); mVideoDecoder.configure(format,new Surface(surface),null,0); mVideoDecoder.start(); startDecodeThread(); } catch (IOException e) { e.printStackTrace(); } return mVideoSize; }
@Override public void setup() throws IOException { mExtractor.selectTrack(mTrackIndex); mEncoder = MediaCodec.createEncoderByType(mOutputFormat.getString(MediaFormat.KEY_MIME)); mEncoder.configure(mOutputFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mEncoderInputSurfaceWrapper = new InputSurface(mEncoder.createInputSurface()); mEncoder.start(); mEncoderStarted = true; mEncoderOutputBuffers = mEncoder.getOutputBuffers(); MediaFormat inputFormat = mExtractor.getTrackFormat(mTrackIndex); // if (inputFormat.containsKey(MediaUtil.KEY_ROTATION)) { // // Decoded video is rotated automatically in Android 5.0 lollipop. // // Turn off here because we don't want to encode rotated one. // // refer: https://android.googlesource // // .com/platform/frameworks/av/+blame/lollipop-release/media/libstagefright/Utils.cpp // inputFormat.setInteger(MediaUtil.KEY_ROTATION, 0); // } mDecoderOutputSurfaceWrapper = new OutputSurface(mSurfaceRender); mDecoder = MediaCodec.createDecoderByType(inputFormat.getString(MediaFormat.KEY_MIME)); mDecoder.configure(inputFormat, mDecoderOutputSurfaceWrapper.getSurface(), null, 0); mDecoder.start(); mDecoderStarted = true; mDecoderInputBuffers = mDecoder.getInputBuffers(); }
/** * Reads bytes from the given recorder and encodes them with the given encoder. * Uses the (deprecated) Synchronous Processing using Buffer Arrays. * <p/> * Encoders (or codecs that generate compressed data) will create and return the codec specific * data before any valid output buffer in output buffers marked with the codec-config flag. * Buffers containing codec-specific-data have no meaningful timestamps. */ @TargetApi(Build.VERSION_CODES.JELLY_BEAN) private void recorderEncoderLoop(MediaCodec codec, SpeechRecord speechRecord) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { codec.start(); // Getting some buffers (e.g. 4 of each) to communicate with the codec ByteBuffer[] codecInputBuffers = codec.getInputBuffers(); ByteBuffer[] codecOutputBuffers = codec.getOutputBuffers(); Log.i("input buffers " + codecInputBuffers.length + "; output buffers: " + codecOutputBuffers.length); boolean doneSubmittingInput = false; int numRetriesDequeueOutputBuffer = 0; int index; while (true) { if (!doneSubmittingInput) { index = codec.dequeueInputBuffer(DEQUEUE_TIMEOUT); if (index >= 0) { int size = queueInputBuffer(codec, codecInputBuffers, index, speechRecord); if (size == -1) { codec.queueInputBuffer(index, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM); Log.i("enc: in: EOS"); doneSubmittingInput = true; } else { Log.i("enc: in: " + size); mNumBytesSubmitted += size; } } else { Log.i("enc: in: timeout, will try again"); } } MediaCodec.BufferInfo info = new MediaCodec.BufferInfo(); index = codec.dequeueOutputBuffer(info, DEQUEUE_TIMEOUT); Log.i("enc: out: flags/index: " + info.flags + "/" + index); if (index == MediaCodec.INFO_TRY_AGAIN_LATER) { Log.i("enc: out: INFO_TRY_AGAIN_LATER: " + numRetriesDequeueOutputBuffer); if (++numRetriesDequeueOutputBuffer > MAX_NUM_RETRIES_DEQUEUE_OUTPUT_BUFFER) { break; } } else if (index == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat format = codec.getOutputFormat(); Log.i("enc: out: INFO_OUTPUT_FORMAT_CHANGED: " + format.toString()); } else if (index == MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED) { codecOutputBuffers = codec.getOutputBuffers(); Log.i("enc: out: INFO_OUTPUT_BUFFERS_CHANGED"); } else { dequeueOutputBuffer(codec, codecOutputBuffers, index, info); mNumBytesDequeued += info.size; if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) { Log.i("enc: out: EOS"); break; } } } codec.stop(); codec.release(); } }
private static MediaCodec configureDecoder(ImageInfo info, int maxInputSize, Surface surface) { if (mDecoderSupportedSize.getWidth() < info.size.getWidth() || mDecoderSupportedSize.getHeight() < info.size.getHeight()) { Log.w(TAG, "HEVC image may exceed decoder capability"); } try { MediaCodec decoder = MediaCodec.createByCodecName(mDecoderName); MediaFormat inputFormat = MediaFormat.createVideoFormat( MediaFormat.MIMETYPE_VIDEO_HEVC, info.size.getWidth(), info.size.getHeight()); inputFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, maxInputSize); inputFormat.setByteBuffer("csd-0", info.paramset); Log.d(TAG, "HEVC input-format=" + inputFormat); decoder.configure(inputFormat, surface, null, 0); return decoder; } catch (IOException ex) { throw new RuntimeException("no HEVC decoding support"); } }
@TargetApi(Build.VERSION_CODES.LOLLIPOP) public static List<String> getAvailableEncoders(int sampleRate) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { MediaFormat format = MediaFormatFactory.createMediaFormat(MediaFormatFactory.Type.FLAC, sampleRate); MediaCodecList mcl = new MediaCodecList(MediaCodecList.REGULAR_CODECS); String encoderAsStr = mcl.findEncoderForFormat(format); List<String> encoders = new ArrayList<>(); for (MediaCodecInfo info : mcl.getCodecInfos()) { if (info.isEncoder()) { if (info.getName().equals(encoderAsStr)) { encoders.add("*** " + info.getName() + ": " + TextUtils.join(", ", info.getSupportedTypes())); } else { encoders.add(info.getName() + ": " + TextUtils.join(", ", info.getSupportedTypes())); } } } return encoders; } return Collections.emptyList(); }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) @Override protected void recorderLoop(SpeechRecord speechRecord) { mNumBytesSubmitted = 0; mNumBytesDequeued = 0; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { MediaFormat format = MediaFormatFactory.createMediaFormat(MediaFormatFactory.Type.FLAC, getSampleRate()); List<String> componentNames = AudioUtils.getEncoderNamesForType(format.getString(MediaFormat.KEY_MIME)); for (String componentName : componentNames) { Log.i("component/format: " + componentName + "/" + format); MediaCodec codec = AudioUtils.createCodec(componentName, format); if (codec != null) { recorderEncoderLoop(codec, speechRecord); if (Log.DEBUG) { AudioUtils.showMetrics(format, mNumBytesSubmitted, mNumBytesDequeued); } break; // TODO: we use the first one that is suitable } } } }
private MediaFormat createMediaCodecFormat(int colorFmt, int width, int height, Integer profile, Integer level){ String mime = mEncodeFormat.getValue(); // "video/avc" MediaFormat mediaFormat = MediaFormat.createVideoFormat(mime, width, height); mediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, colorFmt); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, mBitRate); mediaFormat.setFloat(MediaFormat.KEY_FRAME_RATE, (float) mFrameRate*1.0f); mediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, mIFrameInterval); if(null != profile) { //mediaFormat.setInteger(MediaFormat.KEY_PROFILE, MediaCodecInfo.CodecProfileLevel.AVCProfileHigh); mediaFormat.setInteger(MediaFormat.KEY_PROFILE, profile.intValue()); } if(null != level) { //mediaFormat.setInteger(MediaFormat.KEY_LEVEL, MediaCodecInfo.CodecProfileLevel.AVCLevel4); //mediaFormat.setInteger(MediaFormat.KEY_LEVEL, level.intValue()); } return mediaFormat; }
private MediaCodec createMediaCodec(int bufferSize) throws IOException { MediaCodec mediaCodec = MediaCodec.createEncoderByType("audio/mp4a-latm"); MediaFormat mediaFormat = new MediaFormat(); mediaFormat.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); mediaFormat.setInteger(MediaFormat.KEY_SAMPLE_RATE, SAMPLE_RATE); mediaFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, CHANNELS); mediaFormat.setInteger(MediaFormat.KEY_MAX_INPUT_SIZE, bufferSize); mediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); mediaFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); try { mediaCodec.configure(mediaFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); } catch (Exception e) { Log.w(TAG, e); mediaCodec.release(); throw new IOException(e); } return mediaCodec; }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN) public static MediaFormat createMediaFormat(Type type, int sampleRate) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { MediaFormat format = new MediaFormat(); // TODO: this causes a crash in MediaCodec.configure //format.setString(MediaFormat.KEY_FRAME_RATE, null); format.setInteger(MediaFormat.KEY_SAMPLE_RATE, sampleRate); format.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); if (type == Type.AAC) { format.setString(MediaFormat.KEY_MIME, "audio/mp4a-latm"); format.setInteger(MediaFormat.KEY_AAC_PROFILE, 2); // TODO: or 39? format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); } else if (type == Type.FLAC) { //format.setString(MediaFormat.KEY_MIME, MediaFormat.MIMETYPE_AUDIO_FLAC); // API=21 format.setString(MediaFormat.KEY_MIME, "audio/flac"); format.setInteger(MediaFormat.KEY_BIT_RATE, 64000); //TODO: use another bit rate, does not seem to have effect always //format.setInteger(MediaFormat.KEY_BIT_RATE, 128000); } else { format.setString(MediaFormat.KEY_MIME, "audio/amr-wb"); format.setInteger(MediaFormat.KEY_BIT_RATE, 23050); } return format; } return null; }
public static TrackResult getFirstVideoAndAudioTrack(MediaExtractor extractor) { TrackResult trackResult = new TrackResult(); trackResult.mVideoTrackIndex = -1; trackResult.mAudioTrackIndex = -1; int trackCount = extractor.getTrackCount(); for (int i = 0; i < trackCount; i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (trackResult.mVideoTrackIndex < 0 && mime.startsWith("video/")) { trackResult.mVideoTrackIndex = i; trackResult.mVideoTrackMime = mime; trackResult.mVideoTrackFormat = format; } else if (trackResult.mAudioTrackIndex < 0 && mime.startsWith("audio/")) { trackResult.mAudioTrackIndex = i; trackResult.mAudioTrackMime = mime; trackResult.mAudioTrackFormat = format; } if (trackResult.mVideoTrackIndex >= 0 && trackResult.mAudioTrackIndex >= 0) break; } if (trackResult.mVideoTrackIndex < 0 || trackResult.mAudioTrackIndex < 0) { throw new IllegalArgumentException("extractor does not contain video and/or audio tracks."); } return trackResult; }
private static MediaFormat mediaFormatFromStaticPayloadType(String m, int p) { MediaFormat format = null; PayloadFormat payloadFormat = PayloadFormat.staticPayloadType(p); if (payloadFormat != null) { switch (m.toLowerCase()) { case "audio": format = MediaFormat.createAudioFormat( payloadFormat.mimeType, payloadFormat.clockRate, payloadFormat.channelCount); break; case "video": // TODO: Video not supported. Not sure how to get video dimensions //format = MediaFormat.createVideoFormat(); // Perhaps just set MIME type //format = new MediaFormat(); //format.setString(MediaFormat.KEY_MIME, payloadFormat.mimeType); break; } } return format; }
public AudioEncoderCore(MMediaMuxer MMediaMuxer) throws IOException { super(MMediaMuxer); final MediaFormat audioFormat = MediaFormat.createAudioFormat(MIME_TYPE, SAMPLE_RATE, 1); audioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); audioFormat.setInteger(MediaFormat.KEY_CHANNEL_MASK, AudioFormat.CHANNEL_IN_MONO); audioFormat.setInteger(MediaFormat.KEY_BIT_RATE, BIT_RATE); audioFormat.setInteger(MediaFormat.KEY_CHANNEL_COUNT, 1); // audioFormat.setLong(MediaFormat.KEY_MAX_INPUT_SIZE, inputFile.length()); // audioFormat.setLong(MediaFormat.KEY_DURATION, (long)durationInMs ); if (VERBOSE) Log.i(TAG, "format: " + audioFormat); mEncoder = MediaCodec.createEncoderByType(MIME_TYPE); mEncoder.configure(audioFormat, null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mEncoder.start(); if (mAudioThread == null) { mAudioThread = new AudioThread(); mAudioThread.start(); capturing=true; stopped=false; } }
@Override protected void onOutputFormatChanged(MediaCodec codec, MediaFormat outputFormat) throws ExoPlaybackException { boolean passthrough = passthroughMediaFormat != null; String mimeType = passthrough ? passthroughMediaFormat.getString(MediaFormat.KEY_MIME) : MimeTypes.AUDIO_RAW; MediaFormat format = passthrough ? passthroughMediaFormat : outputFormat; int channelCount = format.getInteger(MediaFormat.KEY_CHANNEL_COUNT); int sampleRate = format.getInteger(MediaFormat.KEY_SAMPLE_RATE); int[] channelMap; if (codecNeedsDiscardChannelsWorkaround && channelCount == 6 && this.channelCount < 6) { channelMap = new int[this.channelCount]; for (int i = 0; i < this.channelCount; i++) { channelMap[i] = i; } } else { channelMap = null; } try { audioTrack.configure(mimeType, channelCount, sampleRate, pcmEncoding, 0, channelMap); } catch (AudioTrack.ConfigurationException e) { throw ExoPlaybackException.createForRenderer(e, getIndex()); } }
/** Create a {@link MpegEncoder} from this {@link Builder}. */ @NonNull public final MpegEncoder to(@NonNull String path, int width, int height) { final MediaFormat format = MediaFormat.createVideoFormat(MIME_TYPE, width, height); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); format.setInteger(MediaFormat.KEY_BIT_RATE, calcBitRate(width * height, mFPS, mMotion)); format.setInteger(MediaFormat.KEY_FRAME_RATE, mFPS); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, mIFrame); try { return new MpegEncoder(this, format, path); } catch (IOException exception) { throw new RuntimeException(exception); } }
/** * Returns a {@link MediaFormat} representation of this format. */ @SuppressLint("InlinedApi") @TargetApi(16) public final MediaFormat getFrameworkMediaFormatV16() { MediaFormat format = new MediaFormat(); format.setString(MediaFormat.KEY_MIME, sampleMimeType); maybeSetStringV16(format, MediaFormat.KEY_LANGUAGE, language); maybeSetIntegerV16(format, MediaFormat.KEY_MAX_INPUT_SIZE, maxInputSize); maybeSetIntegerV16(format, MediaFormat.KEY_WIDTH, width); maybeSetIntegerV16(format, MediaFormat.KEY_HEIGHT, height); maybeSetFloatV16(format, MediaFormat.KEY_FRAME_RATE, frameRate); maybeSetIntegerV16(format, "rotation-degrees", rotationDegrees); maybeSetIntegerV16(format, MediaFormat.KEY_CHANNEL_COUNT, channelCount); maybeSetIntegerV16(format, MediaFormat.KEY_SAMPLE_RATE, sampleRate); maybeSetIntegerV16(format, "encoder-delay", encoderDelay); maybeSetIntegerV16(format, "encoder-padding", encoderPadding); for (int i = 0; i < initializationData.size(); i++) { format.setByteBuffer("csd-" + i, ByteBuffer.wrap(initializationData.get(i))); } maybeSetColorInfoV24(format, colorInfo); return format; }
/** * Selects the video track, if any. * * @return the track index, or -1 if no video track is found. */ private static int selectTrack(MediaExtractor extractor) { // Select the first video track we find, ignore the rest. int numTracks = extractor.getTrackCount(); for (int i = 0; i < numTracks; i++) { MediaFormat format = extractor.getTrackFormat(i); String mime = format.getString(MediaFormat.KEY_MIME); if (mime.startsWith("video/")) { if (VERBOSE) { Log.d(TAG, "Extractor selected track " + i + " (" + mime + "): " + format); } return i; } } return -1; }
private static void setAacFormatSpecificData(MediaFormat format, Fmtp fmtp) { String params = fmtp.formatSpecificParams; String configString = null; String[] paramsSplit = params.split(";"); for (String param : paramsSplit) { param = param.trim(); String[] paramSplit = param.split("="); if (paramSplit[0].toLowerCase().equals("config") && paramSplit.length == 2) { configString = paramSplit[1]; } } format.setByteBuffer("csd-0", ByteBuffer.wrap(Utils.hexStringToByteArray(configString))); }
public void startRecord() throws IOException { synchronized (REC_LOCK){ isRecordStarted=true; MediaFormat audioFormat=mConfig.getAudioFormat(); mAudioEncoder=MediaCodec.createEncoderByType(audioFormat.getString(MediaFormat.KEY_MIME)); mAudioEncoder.configure(audioFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE); MediaFormat videoFormat=mConfig.getVideoFormat(); mVideoEncoder=MediaCodec.createEncoderByType(videoFormat.getString(MediaFormat.KEY_MIME)); //此处不能用mOutputSurface,会configure失败 mVideoEncoder.configure(videoFormat,null,null,MediaCodec.CONFIGURE_FLAG_ENCODE); mEncodeSurface=mVideoEncoder.createInputSurface(); mAudioEncoder.start(); mVideoEncoder.start(); mMuxer=new MediaMuxer(mOutputPath,MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4); mRecordBufferSize = AudioRecord.getMinBufferSize(mRecordSampleRate, mRecordChannelConfig, mRecordAudioFormat)*2; // buffer=new byte[bufferSize]; mAudioRecord=new AudioRecord(MediaRecorder.AudioSource.MIC,mRecordSampleRate,mRecordChannelConfig, mRecordAudioFormat,mRecordBufferSize); mAudioThread=new Thread(new Runnable() { @Override public void run() { mAudioRecord.startRecording(); while (!audioEncodeStep(isTryStopAudio)){}; mAudioRecord.stop(); } }); mAudioThread.start(); isRecordAudioStarted=true; } }
public Configuration(int width,int height){ mAudioFormat=MediaFormat.createAudioFormat("audio/mp4a-latm",48000,2); mAudioFormat.setInteger(MediaFormat.KEY_BIT_RATE,128000); mAudioFormat.setInteger(MediaFormat.KEY_AAC_PROFILE, MediaCodecInfo.CodecProfileLevel.AACObjectLC); mVideoFormat=MediaFormat.createVideoFormat("video/avc",width,height); mVideoFormat.setInteger(MediaFormat.KEY_FRAME_RATE,24); mVideoFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,1); mVideoFormat.setInteger(MediaFormat.KEY_BIT_RATE,width*height*5); mVideoFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT,MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); }
/** * assign encoder to muxer * @param format * @return minus value indicate error */ /*package*/ synchronized int addTrack(final MediaFormat format) { if (mIsStarted) throw new IllegalStateException("muxer already started"); final int trackIx = mMediaMuxer.addTrack(format); if (DEBUG) Log.i(TAG, "addTrack:trackNum=" + mEncoderCount + ",trackIx=" + trackIx + ",format=" + format); return trackIx; }
protected MediaFormat convertVideoConfigToFormat(MediaConfig.Video config){ MediaFormat format=MediaFormat.createVideoFormat(config.mime,config.width,config.height); format.setInteger(MediaFormat.KEY_BIT_RATE,config.bitrate); format.setInteger(MediaFormat.KEY_FRAME_RATE,config.frameRate); format.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL,config.iframe); format.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); return format; }
@TargetApi(Build.VERSION_CODES.KITKAT) @Override public IMediaFormat getFormat() { if (mTrackInfo == null) return null; if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) return null; MediaFormat mediaFormat = mTrackInfo.getFormat(); if (mediaFormat == null) return null; return new AndroidMediaFormat(mediaFormat); }
private synchronized boolean videoEncodeStep(boolean isEnd){ AvLog.d(TAG,"videoEncodeStep:"+isEncodeStarted+"/"+isEnd); if(isEncodeStarted){ if(isEnd){ mVideoEncoder.signalEndOfInputStream(); } MediaCodec.BufferInfo info=new MediaCodec.BufferInfo(); while (true){ int mOutputIndex=mVideoEncoder.dequeueOutputBuffer(info,TIME_OUT); AvLog.i(TAG,"videoEncodeStep:mOutputIndex="+mOutputIndex); if(mOutputIndex>=0){ if((info.flags&MediaCodec.BUFFER_FLAG_CODEC_CONFIG)!=0){ info.size=0; } ByteBuffer buffer= CodecUtil.getOutputBuffer(mVideoEncoder,mOutputIndex); if(mStore!=null){ mStore.addData(mVideoTrack,new HardMediaData(buffer,info)); } mVideoEncoder.releaseOutputBuffer(mOutputIndex,false); if((info.flags&MediaCodec.BUFFER_FLAG_END_OF_STREAM)!=0){ closeVideoEncoder(); isEncodeStarted=false; AvLog.i(TAG,"videoEncodeStep: MediaCodec.BUFFER_FLAG_END_OF_STREAM "); break; } }else if(mOutputIndex== MediaCodec.INFO_OUTPUT_FORMAT_CHANGED){ MediaFormat format=mVideoEncoder.getOutputFormat(); if(mStore!=null){ mVideoTrack=mStore.addTrack(format); } }else if(mOutputIndex== MediaCodec.INFO_TRY_AGAIN_LATER&&!isEnd){ break; } } } return false; }
public AACEncoder(final StreamPublisher.StreamPublisherParam params) throws IOException { this.samplingRate = params.samplingRate; bufferSize = params.audioBufferSize; mMediaCodec = MediaCodec.createEncoderByType(params.audioMIME); mMediaCodec.configure(params.createAudioMediaFormat(), null, null, MediaCodec.CONFIGURE_FLAG_ENCODE); mediaCodecInputStream = new MediaCodecInputStream(mMediaCodec, new MediaCodecInputStream.MediaFormatCallback() { @Override public void onChangeMediaFormat(MediaFormat mediaFormat) { params.setAudioOutputMediaFormat(mediaFormat); } }); mAudioRecord = new AudioRecord(MediaRecorder.AudioSource.MIC, samplingRate, AudioFormat.CHANNEL_IN_STEREO, AudioFormat.ENCODING_PCM_16BIT, bufferSize); }
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) private void getDataFromSurfaceAPI21() { thread = new Thread(new Runnable() { @Override public void run() { while (!Thread.interrupted()) { for (; ; ) { int outBufferIndex = videoEncoder.dequeueOutputBuffer(videoInfo, 0); if (outBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat mediaFormat = videoEncoder.getOutputFormat(); getH264Data.onVideoFormat(mediaFormat); getH264Data.onSPSandPPS(mediaFormat.getByteBuffer("csd-0"), mediaFormat.getByteBuffer("csd-1")); spsPpsSetted = true; } else if (outBufferIndex >= 0) { //This ByteBuffer is H264 ByteBuffer bb = videoEncoder.getOutputBuffer(outBufferIndex); if ((videoInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { if (!spsPpsSetted) { Pair<ByteBuffer, ByteBuffer> buffers = decodeSpsPpsFromBuffer(bb.duplicate(), videoInfo.size); if (buffers != null) { getH264Data.onSPSandPPS(buffers.first, buffers.second); spsPpsSetted = true; } } } videoInfo.presentationTimeUs = System.nanoTime() / 1000 - mPresentTimeUs; getH264Data.getH264Data(bb, videoInfo); videoEncoder.releaseOutputBuffer(outBufferIndex, false); } else { break; } } } } }); thread.start(); }
private void getDataFromSurface() { thread = new Thread(new Runnable() { @Override public void run() { while (!Thread.interrupted()) { ByteBuffer[] outputBuffers = videoEncoder.getOutputBuffers(); for (; ; ) { int outBufferIndex = videoEncoder.dequeueOutputBuffer(videoInfo, 0); if (outBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) { MediaFormat mediaFormat = videoEncoder.getOutputFormat(); getH264Data.onVideoFormat(mediaFormat); getH264Data.onSPSandPPS(mediaFormat.getByteBuffer("csd-0"), mediaFormat.getByteBuffer("csd-1")); spsPpsSetted = true; } else if (outBufferIndex >= 0) { //This ByteBuffer is H264 ByteBuffer bb = outputBuffers[outBufferIndex]; if ((videoInfo.flags & MediaCodec.BUFFER_FLAG_CODEC_CONFIG) != 0) { if (!spsPpsSetted) { Pair<ByteBuffer, ByteBuffer> buffers = decodeSpsPpsFromBuffer(bb.duplicate(), videoInfo.size); if (buffers != null) { getH264Data.onSPSandPPS(buffers.first, buffers.second); spsPpsSetted = true; } } } videoInfo.presentationTimeUs = System.nanoTime() / 1000 - mPresentTimeUs; getH264Data.getH264Data(bb, videoInfo); videoEncoder.releaseOutputBuffer(outBufferIndex, false); } else { break; } } } } }); thread.start(); }
/** * assign encoder to muxer * * @param format * @return minus value indicate error */ /*package*/ synchronized int addTrack(final MediaFormat format) { if (mIsStarted) throw new IllegalStateException("muxer already started"); final int trackIx = mMediaMuxer.addTrack(format); if (DEBUG) Log.i(TAG, "addTrack:trackNum=" + mEncoderCount + ",trackIx=" + trackIx + ",format=" + format); return trackIx; }
@Override protected void configureCodec(MediaCodecInfo codecInfo, MediaCodec codec, Format format, MediaCrypto crypto) throws DecoderQueryException { codecMaxValues = getCodecMaxValues(codecInfo, format, streamFormats); MediaFormat mediaFormat = getMediaFormat(format, codecMaxValues, deviceNeedsAutoFrcWorkaround, tunnelingAudioSessionId); codec.configure(mediaFormat, surface, crypto, 0); if (Util.SDK_INT >= 23 && tunneling) { tunnelingOnFrameRenderedListener = new OnFrameRenderedListenerV23(codec); } }
public static MediaFormat getFormat () { MediaFormat mMediaFormat = MediaFormat.createVideoFormat(AccessConstants.FORMAT, AccessConstants.PHONE_WIDTH, AccessConstants.PHONE_HEIGHT); mMediaFormat.setInteger(MediaFormat.KEY_BIT_RATE, AccessConstants.BITRATE); mMediaFormat.setInteger(MediaFormat.KEY_FRAME_RATE, AccessConstants.FPS); mMediaFormat.setInteger(MediaFormat.KEY_COLOR_FORMAT, MediaCodecInfo.CodecCapabilities.COLOR_FormatSurface); mMediaFormat.setInteger(MediaFormat.KEY_I_FRAME_INTERVAL, 1); return mMediaFormat; }
@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2) private void resetOutputFormat() { // should happen before receiving buffers, and should only happen once if (mMuxerStarted) { throw new IllegalStateException("output format already changed!"); } MediaFormat newFormat = mEncoder.getOutputFormat(); newFormat.getByteBuffer("csd-0"); // SPS newFormat.getByteBuffer("csd-1"); // PPS Log.i(TAG, "output format changed.\n new format: " + newFormat.toString()); mVideoTrackIndex = mMuxer.addTrack(newFormat); mMuxer.start(); mMuxerStarted = true; Log.i(TAG, "started media muxer, videoIndex=" + mVideoTrackIndex); }
private String findCoderForFormat(MediaFormat format, boolean findEncoder) { String mimeType = format.getString(MediaFormat.KEY_MIME); Iterator<MediaCodecInfo> iterator = new MediaCodecInfoIterator(); while (iterator.hasNext()) { MediaCodecInfo codecInfo = iterator.next(); if (codecInfo.isEncoder() != findEncoder) continue; if (Arrays.asList(codecInfo.getSupportedTypes()).contains(mimeType)) { return codecInfo.getName(); } } return null; }
private void setupTrackTranscoders(MediaFormatStrategy formatStrategy) { MediaExtractorUtils.TrackResult trackResult = MediaExtractorUtils.getFirstVideoAndAudioTrack(mExtractor); MediaFormat videoOutputFormat = formatStrategy.createVideoOutputFormat(trackResult.mVideoTrackFormat); MediaFormat audioOutputFormat = formatStrategy.createAudioOutputFormat(trackResult.mAudioTrackFormat); if (videoOutputFormat == null && audioOutputFormat == null) { throw new InvalidOutputFormatException("MediaFormatStrategy returned pass-through for both video and audio. No transcoding is necessary."); } QueuedMuxer queuedMuxer = new QueuedMuxer(mMuxer, new QueuedMuxer.Listener() { @Override public void onDetermineOutputFormat() { MediaFormatValidator.validateVideoOutputFormat(mVideoTrackTranscoder.getDeterminedFormat()); MediaFormatValidator.validateAudioOutputFormat(mAudioTrackTranscoder.getDeterminedFormat()); } }); if (videoOutputFormat == null) { mVideoTrackTranscoder = new PassThroughTrackTranscoder(mExtractor, trackResult.mVideoTrackIndex, queuedMuxer, QueuedMuxer.SampleType.VIDEO); } else { mVideoTrackTranscoder = new VideoTrackTranscoder(mExtractor, trackResult.mVideoTrackIndex, videoOutputFormat, queuedMuxer); } mVideoTrackTranscoder.setup(); if (audioOutputFormat == null) { mAudioTrackTranscoder = new PassThroughTrackTranscoder(mExtractor, trackResult.mAudioTrackIndex, queuedMuxer, QueuedMuxer.SampleType.AUDIO); } else { mAudioTrackTranscoder = new AudioTrackTranscoder(mExtractor, trackResult.mAudioTrackIndex, audioOutputFormat, queuedMuxer); } mAudioTrackTranscoder.setup(); mExtractor.selectTrack(trackResult.mVideoTrackIndex); mExtractor.selectTrack(trackResult.mAudioTrackIndex); }
public AudioTrackTranscoder(MediaExtractor extractor, int trackIndex, MediaFormat outputFormat, QueuedMuxer muxer) { mExtractor = extractor; mTrackIndex = trackIndex; mOutputFormat = outputFormat; mMuxer = muxer; mInputFormat = mExtractor.getTrackFormat(mTrackIndex); }
public static void validateVideoOutputFormat(MediaFormat format) { String mime = format.getString(MediaFormat.KEY_MIME); // Refer: http://developer.android.com/guide/appendix/media-formats.html#core // Refer: http://en.wikipedia.org/wiki/MPEG-4_Part_14#Data_streams if (!MediaFormatExtraConstants.MIMETYPE_VIDEO_AVC.equals(mime)) { throw new InvalidOutputFormatException("Video codecs other than AVC is not supported, actual mime type: " + mime); } ByteBuffer spsBuffer = AvcCsdUtils.getSpsBuffer(format); byte profileIdc = AvcSpsUtils.getProfileIdc(spsBuffer); if (profileIdc != PROFILE_IDC_BASELINE) { throw new InvalidOutputFormatException("Non-baseline AVC video profile is not supported by Android OS, actual profile_idc: " + profileIdc); } }