请尊重分享成果,转载请注明出处,本文来自逆流的鱼yuiop,原文链接:http://blog.csdn.net/hejjunlin/article/details/53729575

前言:前面几章都是分析MediaCodec相关源码,有收到提问,说MediaCodec到底是硬解码还是软解码?看下今天的Agenda:

  • MediaCodec到底是硬解码还是软解码
  • MediaMuxer初识
  • MediaMuxer与MediaExtractor进行剪辑视频
  • 效果图
  • 布局实现
  • 逻辑实现
  • log输出过程

MediaCodec到底是硬解码还是软解码?

MediaCodec 调用的是在系统中register的解码器,硬件厂商会把自己的硬解码器register进来,就是硬解,如果他register一个软解码器,则是软解。

MediaCodec并不是真正的codec,真正codec是在openMax,要保证是硬解,在MediaCodec里有接口可以枚举所有解码器,每种编码可能都有多个解码器,区分哪个是软解哪个是硬解就行。

  1. MediaCodec mediaCodec = MediaCodec.createDecoderByType("video/avc");

我的应用里面接收的是H264编码数据,所以我选取的是video/avc,我们可以看一下MediaCodec.createDecoderByType()枚举了哪些解编码器:

  1. > /**
  2. > * Instantiate a decoder supporting input data of the given mime type.
  3. > *
  4. > * The following is a partial list of defined mime types and their semantics:
  5. > * <ul>
  6. > * <li>"video/x-vnd.on2.vp8" - VP8 video (i.e. video in .webm)
  7. > * <li>"video/x-vnd.on2.vp9" - VP9 video (i.e. video in .webm)
  8. > * <li>"video/avc" - H.264/AVC video
  9. > * <li>"video/mp4v-es" - MPEG4 video
  10. > * <li>"video/3gpp" - H.263 video
  11. > * <li>"audio/3gpp" - AMR narrowband audio
  12. > * <li>"audio/amr-wb" - AMR wideband audio
  13. > * <li>"audio/mpeg" - MPEG1/2 audio layer III
  14. > * <li>"audio/mp4a-latm" - AAC audio (note, this is raw AAC packets, not packaged in LATM!)
  15. > * <li>"audio/vorbis" - vorbis audio
  16. > * <li>"audio/g711-alaw" - G.711 alaw audio
  17. > * <li>"audio/g711-mlaw" - G.711 ulaw audio
  18. > * </ul>
  19. > *
  20. > * @param type The mime type of the input data.
  21. > */
  22. > public static MediaCodec createDecoderByType(String type) {
  23. > return new MediaCodec(type, true /* nameIsType */, false /* encoder */);
  24. > }

可以看到我选的”video/avc” - H.264/AVC video是一种H264的解码方式,但并不能证明我使用的就一定是硬解码

我们先来看一下Android系统中解码器的命名,软解码器通常是以OMX.google开头的。硬解码器通常是以OMX.[hardware_vendor]开头的,比如TI的解码器是以OMX.TI开头的。当然还有一些不遵守这个命名规范的,不以OMX.开头的,那也会被认为是软解码器。

判断规则见frameworks/av/media/libstagefright/OMXCodec.cpp:

  1. static bool IsSoftwareCodec(const char *componentName) {
  2. if (!strncmp("OMX.google.", componentName, 11)) {
  3. return true;
  4. }
  5. if (!strncmp("OMX.", componentName, 4)) {
  6. return false;
  7. }
  8. return true;
  9. }

其实MediaCodec调用的是在系统中注册的解码器,系统中存在的解码器可以很多,但能够被应用使用的解码器是根据配置来的,即/system/etc/media_codecc.xml。这个文件一般由硬件或者系统的生产厂家在build整个系统的时候提供,一般是保存在代码的device/[company]/[codename]目录下的,例如device/samsung/tuna/media_codecs.xml。这个文件配置了系统中有哪些可用的codec以及,这些codec对应的媒体文件类型。在这个文件里面,系统里面提供的软硬codec都需要被列出来。

也就是说,如果系统里面实际上包含了某个codec,但是并没有被配置在这个文件里,那么应用程序也无法使用到。

在这个配置文件里面,如果出现多个codec对应同样类型的媒体格式的时候,这些codec都会被保留起来。当系统使用的时候,将会选择第一个匹配的codec。除非是指明了要软解码还是硬解码,但是Android的framework层为上层提供服务的AwesomePlayer中在处理音频和视频的时候,对到底是选择软解还是硬解的参数没有设置。所以虽然底层是支持选择的,但是对于上层使用MediaPlayer的Java程序来说,还是只能接受默认的codec选取规则。

但是Android提供的命令行程序/system/bin/stagefright在播放音频文件的时候,倒是可以根据参数来选择到底使用软解码还是硬解码,但是该工具只支持播放音频,不支持播放视频。

一般来说,如果系统里面有对应的媒体硬件解码器的话,系统开发人员应该是会配置在media_codecs.xml中,所以大多数情况下,如果有硬件解码器,那么我们总是会使用到硬件解码器。极少数情况下,硬件解码器存在,但不配置,我猜只可能是这个硬解码器还有bug,暂时还不适合发布,所以不用使用。

MediaMuxer初识

今天主要介绍MediaMuxer,在Android的多媒体类中,MediaMuxer用于将音频和视频进行混合生成多媒体文件。缺点是目前只能支持一个audio track和一个video track,而且仅支持mp4输出。

通过一个案列来了解MediaMuxer,以便后续过程分析,这个案例是进行一个音视频剪辑。就是一段正常的音视频文件,剪辑其中一个片段。在我的手机上有一段叫《节目.mp4》音视频文件。想剪辑其中精华部分,从2秒到12秒的视频。如下为效果图

效果图:

输入剪辑时间点,可以动态设置,并不是写死,剪辑时长,也是可以动态设置。





节目_output.mp4就是剪辑后的音视频文件。



布局实现:

  1. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  2. android:id="@+id/container"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:orientation="vertical">
  6. <LinearLayout
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content"
  9. android:padding="10dp"
  10. android:orientation="horizontal">
  11. <TextView
  12. android:layout_width="wrap_content"
  13. android:layout_height="wrap_content"
  14. android:textSize="18sp"
  15. android:text="开始剪辑点(从第几秒开始):"/>
  16. <EditText
  17. android:id="@+id/et_cutpoint"
  18. android:layout_width="match_parent"
  19. android:layout_height="wrap_content"
  20. android:background="@null"
  21. android:textSize="18sp"
  22. android:layout_marginLeft="5dp"
  23. android:hint="2"/>
  24. </LinearLayout>
  25. <LinearLayout
  26. android:layout_width="match_parent"
  27. android:layout_height="wrap_content"
  28. android:padding="10dp"
  29. android:orientation="horizontal">
  30. <TextView
  31. android:layout_width="wrap_content"
  32. android:layout_height="wrap_content"
  33. android:textSize="18sp"
  34. android:text="剪辑时长(剪辑多少秒):"/>
  35. <EditText
  36. android:id="@+id/et_cutduration"
  37. android:layout_width="match_parent"
  38. android:layout_height="wrap_content"
  39. android:background="@null"
  40. android:textSize="18sp"
  41. android:layout_marginLeft="5dp"
  42. android:hint="10"/>
  43. </LinearLayout>
  44. <Button
  45. android:layout_width="wrap_content"
  46. android:layout_height="wrap_content"
  47. android:id="@+id/button"
  48. android:padding="10dp"
  49. android:background="@drawable/selector_green_bg"
  50. android:layout_gravity="center"
  51. android:textColor="@color/white"
  52. android:text="剪切视频" />
  53. </LinearLayout>

本文来自逆流的鱼yuiop,原文链接:http://blog.csdn.net/hejjunlin/article/details/53729575

逻辑实现:

  1. package com.hejunlin.videoclip;
  2. import android.media.MediaCodec;
  3. import android.media.MediaExtractor;
  4. import android.media.MediaFormat;
  5. import android.media.MediaMuxer;
  6. import android.util.Log;
  7. import java.nio.ByteBuffer;
  8. /**
  9. * Created by 逆流的鱼yuiop on 16/12/18.
  10. * blog : http://blog.csdn.net/hejjunlin
  11. */
  12. public class VideoClip {
  13. private final static String TAG = "VideoClip";
  14. private MediaExtractor mMediaExtractor;
  15. private MediaFormat mMediaFormat;
  16. private MediaMuxer mMediaMuxer;
  17. private String mime = null;
  18. public boolean clipVideo(String url, long clipPoint, long clipDuration) {
  19. int videoTrackIndex = -1;
  20. int audioTrackIndex = -1;
  21. int videoMaxInputSize = 0;
  22. int audioMaxInputSize = 0;
  23. int sourceVTrack = 0;
  24. int sourceATrack = 0;
  25. long videoDuration, audioDuration;
  26. Log.d(TAG, ">> url : " + url);
  27. //创建分离器
  28. mMediaExtractor = new MediaExtractor();
  29. try {
  30. //设置文件路径
  31. mMediaExtractor.setDataSource(url);
  32. //创建合成器
  33. mMediaMuxer = new MediaMuxer(url.substring(0, url.lastIndexOf(".")) + "_output.mp4", MediaMuxer.OutputFormat.MUXER_OUTPUT_MPEG_4);
  34. } catch (Exception e) {
  35. Log.e(TAG, "error path" + e.getMessage());
  36. }
  37. //获取每个轨道的信息
  38. for (int i = 0; i < mMediaExtractor.getTrackCount(); i++) {
  39. try {
  40. mMediaFormat = mMediaExtractor.getTrackFormat(i);
  41. mime = mMediaFormat.getString(MediaFormat.KEY_MIME);
  42. if (mime.startsWith("video/")) {
  43. sourceVTrack = i;
  44. int width = mMediaFormat.getInteger(MediaFormat.KEY_WIDTH);
  45. int height = mMediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
  46. videoMaxInputSize = mMediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
  47. videoDuration = mMediaFormat.getLong(MediaFormat.KEY_DURATION);
  48. //检测剪辑点和剪辑时长是否正确
  49. if (clipPoint >= videoDuration) {
  50. Log.e(TAG, "clip point is error!");
  51. return false;
  52. }
  53. if ((clipDuration != 0) && ((clipDuration + clipPoint) >= videoDuration)) {
  54. Log.e(TAG, "clip duration is error!");
  55. return false;
  56. }
  57. Log.d(TAG, "width and height is " + width + " " + height
  58. + ";maxInputSize is " + videoMaxInputSize
  59. + ";duration is " + videoDuration
  60. );
  61. //向合成器添加视频轨
  62. videoTrackIndex = mMediaMuxer.addTrack(mMediaFormat);
  63. } else if (mime.startsWith("audio/")) {
  64. sourceATrack = i;
  65. int sampleRate = mMediaFormat.getInteger(MediaFormat.KEY_SAMPLE_RATE);
  66. int channelCount = mMediaFormat.getInteger(MediaFormat.KEY_CHANNEL_COUNT);
  67. audioMaxInputSize = mMediaFormat.getInteger(MediaFormat.KEY_MAX_INPUT_SIZE);
  68. audioDuration = mMediaFormat.getLong(MediaFormat.KEY_DURATION);
  69. Log.d(TAG, "sampleRate is " + sampleRate
  70. + ";channelCount is " + channelCount
  71. + ";audioMaxInputSize is " + audioMaxInputSize
  72. + ";audioDuration is " + audioDuration
  73. );
  74. //添加音轨
  75. audioTrackIndex = mMediaMuxer.addTrack(mMediaFormat);
  76. }
  77. Log.d(TAG, "file mime is " + mime);
  78. } catch (Exception e) {
  79. Log.e(TAG, " read error " + e.getMessage());
  80. }
  81. }
  82. //分配缓冲
  83. ByteBuffer inputBuffer = ByteBuffer.allocate(videoMaxInputSize);
  84. //根据官方文档的解释MediaMuxer的start一定要在addTrack之后
  85. mMediaMuxer.start();
  86. //视频处理部分
  87. mMediaExtractor.selectTrack(sourceVTrack);
  88. MediaCodec.BufferInfo videoInfo = new MediaCodec.BufferInfo();
  89. videoInfo.presentationTimeUs = 0;
  90. long videoSampleTime;
  91. //获取源视频相邻帧之间的时间间隔。(1)
  92. {
  93. mMediaExtractor.readSampleData(inputBuffer, 0);
  94. //skip first I frame
  95. if (mMediaExtractor.getSampleFlags() == MediaExtractor.SAMPLE_FLAG_SYNC)
  96. mMediaExtractor.advance();
  97. mMediaExtractor.readSampleData(inputBuffer, 0);
  98. long firstVideoPTS = mMediaExtractor.getSampleTime();
  99. mMediaExtractor.advance();
  100. mMediaExtractor.readSampleData(inputBuffer, 0);
  101. long SecondVideoPTS = mMediaExtractor.getSampleTime();
  102. videoSampleTime = Math.abs(SecondVideoPTS - firstVideoPTS);
  103. Log.d(TAG, "videoSampleTime is " + videoSampleTime);
  104. }
  105. //选择起点
  106. mMediaExtractor.seekTo(clipPoint, MediaExtractor.SEEK_TO_PREVIOUS_SYNC);
  107. while (true) {
  108. int sampleSize = mMediaExtractor.readSampleData(inputBuffer, 0);
  109. if (sampleSize < 0) {
  110. //这里一定要释放选择的轨道,不然另一个轨道就无法选中了
  111. mMediaExtractor.unselectTrack(sourceVTrack);
  112. break;
  113. }
  114. int trackIndex = mMediaExtractor.getSampleTrackIndex();
  115. //获取时间戳
  116. long presentationTimeUs = mMediaExtractor.getSampleTime();
  117. //获取帧类型,只能识别是否为I帧
  118. int sampleFlag = mMediaExtractor.getSampleFlags();
  119. Log.d(TAG, "trackIndex is " + trackIndex
  120. + ";presentationTimeUs is " + presentationTimeUs
  121. + ";sampleFlag is " + sampleFlag
  122. + ";sampleSize is " + sampleSize);
  123. //剪辑时间到了就跳出
  124. if ((clipDuration != 0) && (presentationTimeUs > (clipPoint + clipDuration))) {
  125. mMediaExtractor.unselectTrack(sourceVTrack);
  126. break;
  127. }
  128. mMediaExtractor.advance();
  129. videoInfo.offset = 0;
  130. videoInfo.size = sampleSize;
  131. videoInfo.flags = sampleFlag;
  132. mMediaMuxer.writeSampleData(videoTrackIndex, inputBuffer, videoInfo);
  133. videoInfo.presentationTimeUs += videoSampleTime;//presentationTimeUs;
  134. }
  135. //音频部分
  136. mMediaExtractor.selectTrack(sourceATrack);
  137. MediaCodec.BufferInfo audioInfo = new MediaCodec.BufferInfo();
  138. audioInfo.presentationTimeUs = 0;
  139. long audioSampleTime;
  140. //获取音频帧时长
  141. {
  142. mMediaExtractor.readSampleData(inputBuffer, 0);
  143. //skip first sample
  144. if (mMediaExtractor.getSampleTime() == 0)
  145. mMediaExtractor.advance();
  146. mMediaExtractor.readSampleData(inputBuffer, 0);
  147. long firstAudioPTS = mMediaExtractor.getSampleTime();
  148. mMediaExtractor.advance();
  149. mMediaExtractor.readSampleData(inputBuffer, 0);
  150. long SecondAudioPTS = mMediaExtractor.getSampleTime();
  151. audioSampleTime = Math.abs(SecondAudioPTS - firstAudioPTS);
  152. Log.d(TAG, "AudioSampleTime is " + audioSampleTime);
  153. }
  154. mMediaExtractor.seekTo(clipPoint, MediaExtractor.SEEK_TO_CLOSEST_SYNC);
  155. while (true) {
  156. int sampleSize = mMediaExtractor.readSampleData(inputBuffer, 0);
  157. if (sampleSize < 0) {
  158. mMediaExtractor.unselectTrack(sourceATrack);
  159. break;
  160. }
  161. int trackIndex = mMediaExtractor.getSampleTrackIndex();
  162. long presentationTimeUs = mMediaExtractor.getSampleTime();
  163. Log.d(TAG, "trackIndex is " + trackIndex
  164. + ";presentationTimeUs is " + presentationTimeUs);
  165. if ((clipDuration != 0) && (presentationTimeUs > (clipPoint + clipDuration))) {
  166. mMediaExtractor.unselectTrack(sourceATrack);
  167. break;
  168. }
  169. mMediaExtractor.advance();
  170. audioInfo.offset = 0;
  171. audioInfo.size = sampleSize;
  172. mMediaMuxer.writeSampleData(audioTrackIndex, inputBuffer, audioInfo);
  173. audioInfo.presentationTimeUs += audioSampleTime;//presentationTimeUs;
  174. }
  175. //全部写完后释放MediaMuxer和MediaExtractor
  176. mMediaMuxer.stop();
  177. mMediaMuxer.release();
  178. mMediaExtractor.release();
  179. mMediaExtractor = null;
  180. return true;
  181. }
  182. }

ClipActivity

  1. package com.hejunlin.videoclip;
  2. import android.annotation.TargetApi;
  3. import android.os.Build;
  4. import android.os.Bundle;
  5. import android.os.Environment;
  6. import android.support.v7.app.AppCompatActivity;
  7. import android.view.View;
  8. import android.widget.Button;
  9. import android.widget.EditText;
  10. /**
  11. * Created by 逆流的鱼yuiop on 16/12/18.
  12. * blog : http://blog.csdn.net/hejjunlin
  13. */
  14. public class ClipActivity extends AppCompatActivity implements View.OnClickListener {
  15. private Button mButton;
  16. private EditText mCutDuration;
  17. private EditText mCutPoint;
  18. @Override
  19. protected void onCreate(Bundle savedInstanceState) {
  20. super.onCreate(savedInstanceState);
  21. setContentView(R.layout.activity_main1);
  22. mButton = (Button) findViewById(R.id.button);
  23. mCutDuration = (EditText) findViewById(R.id.et_cutduration);
  24. mCutPoint = (EditText)findViewById(R.id.et_cutpoint);
  25. mButton.setOnClickListener(this);
  26. }
  27. @TargetApi(Build.VERSION_CODES.LOLLIPOP)
  28. @Override
  29. public void onClick(View v) {
  30. new VideoClip().clipVideo(
  31. Environment.getExternalStorageDirectory() + "/" + "节目.mp4",
  32. Integer.parseInt(mCutPoint.getText().toString())*1000*1000,
  33. Integer.parseInt(mCutDuration.getText().toString())*1000*1000);
  34. }
  35. }

log输出过程

  1. 12-18 19:04:49.212 22409-22409/com.hejunlin.videoclip
  2. D/VideoClip: >> url : /storage/emulated/0/节目.mp4
  3. 12-18 19:04:49.364 22409-22409/com.hejunlin.videoclip
  4. D/VideoClip: width and height is 480 272;maxInputSize is 25326;duration is 125266666
  5. 12-18 19:04:49.365 22409-22409/com.hejunlin.videoclip
  6. D/VideoClip: file mime is video/avc
  7. 12-18 19:04:49.366 22409-22409/com.hejunlin.videoclip
  8. D/VideoClip: sampleRate is 24000;channelCount is 2;audioMaxInputSize is 348;audioDuration is 125440000
  9. 12-18 19:04:49.366 22409-22409/com.hejunlin.videoclip
  10. D/VideoClip: file mime is audio/mp4a-latm
  11. 12-18 19:04:49.370 22409-22409/com.hejunlin.videoclip
  12. D/VideoClip: videoSampleTime is 66667
  13. 12-18 19:04:49.372 22409-22409/com.hejunlin.videoclip
  14. D/VideoClip: trackIndex is 0;presentationTimeUs is 0;sampleFlag is 1;sampleSize is 19099
  15. 12-18 19:04:49.373 22409-22409/com.hejunlin.videoclip
  16. D/VideoClip: trackIndex is 0;presentationTimeUs is 66666;sampleFlag is 0;sampleSize is 451
  17. 12-18 19:04:49.374 22409-22409/com.hejunlin.videoclip
  18. D/VideoClip: trackIndex is 0;presentationTimeUs is 133333;sampleFlag is 0;sampleSize is 521
  19. 12-18 19:04:49.374 22409-22409/com.hejunlin.videoclip
  20. D/VideoClip: trackIndex is 0;presentationTimeUs is 200000;sampleFlag is 0;sampleSize is 738
  21. 12-18 19:04:49.375 22409-22409/com.hejunlin.videoclip
  22. D/VideoClip: trackIndex is 0;presentationTimeUs is 266666;sampleFlag is 0;sampleSize is 628
  23. 12-18 19:04:49.376 22409-22409/com.hejunlin.videoclip
  24. D/VideoClip: trackIndex is 0;presentationTimeUs is 333333;sampleFlag is 0;sampleSize is 267
  25. 12-18 19:04:49.376 22409-22409/com.hejunlin.videoclip
  26. D/VideoClip: trackIndex is 0;presentationTimeUs is 400000;sampleFlag is 0;sampleSize is 4003
  27. 12-18 19:04:49.377 22409-22409/com.hejunlin.videoclip
  28. D/VideoClip: trackIndex is 0;presentationTimeUs is 466666;sampleFlag is 0;sampleSize is 2575
  29. 12-18 19:04:49.377 22409-22409/com.hejunlin.videoclip
  30. D/VideoClip: trackIndex is 0;presentationTimeUs is 533333;sampleFlag is 0;sampleSize is 1364
  31. 12-18 19:04:49.378 22409-22409/com.hejunlin.videoclip
  32. D/VideoClip: trackIndex is 0;presentationTimeUs is 600000;sampleFlag is 0;sampleSize is 3019
  33. 12-18 19:04:49.379 22409-22409/com.hejunlin.videoclip
  34. D/VideoClip: trackIndex is 0;presentationTimeUs is 666666;sampleFlag is 0;sampleSize is 4595
  35. 12-18 19:04:49.379 22409-22409/com.hejunlin.videoclip
  36. D/VideoClip: trackIndex is 0;presentationTimeUs is 733333;sampleFlag is 0;sampleSize is 3689
  37. ... 省略log
  38. 12-18 19:04:49.467 22409-22409/com.hejunlin.videoclip
  39. D/VideoClip: AudioSampleTime is 42667
  40. 12-18 19:04:49.468 22409-22409/com.hejunlin.videoclip
  41. D/VideoClip: trackIndex is 1;presentationTimeUs is 2005333
  42. 12-18 19:04:49.469 22409-22409/com.hejunlin.videoclip
  43. D/VideoClip: trackIndex is 1;presentationTimeUs is 2048000
  44. 12-18 19:04:49.469 22409-22409/com.hejunlin.videoclip
  45. D/VideoClip: trackIndex is 1;presentationTimeUs is 2090666
  46. 12-18 19:04:49.470 22409-22409/com.hejunlin.videoclip
  47. D/VideoClip: trackIndex is 1;presentationTimeUs is 2133333
  48. 12-18 19:04:49.470 22409-22409/com.hejunlin.videoclip
  49. ... 省略log
  50. D/VideoClip: trackIndex is 1;presentationTimeUs is 12032000

第一时间获得博客更新提醒,以及更多android干货,源码分析,欢迎关注我的微信公众号,扫一扫下方二维码或者长按识别二维码,即可关注。





如果你觉得好,随手点赞,也是对笔者的肯定,也可以分享此公众号给你更多的人,原创不易

Android Multimedia框架总结(二十三)MediaCodec补充及MediaMuxer引入(附案例)的更多相关文章

  1. Android Multimedia框架总结(十三)CodeC部分之OpenMAX框架初识及接口与适配层实现

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52629598 前言:上篇中介绍O ...

  2. Android Multimedia框架总结(十五)Camera框架之Camera2补充

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52751055 前言:监于5.0之 ...

  3. Android Multimedia框架总结(七)C++中MediaPlayer的C/S架构补充及MediaService介绍

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼,文章链接: http://blog.csdn.net/hejjunlin/article/details/52465168 前面一篇主要介绍 ...

  4. Android Multimedia框架总结(十一)CodeC部分之AwesomePlayer到OMX服务

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/52623882 前言:上篇文< ...

  5. Android Multimedia框架总结(九)Stagefright框架之数据处理及到OMXCodec过程

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼:http://blog.csdn.net/hejjunlin/article/details/52532085 不知不觉到第九篇了,感觉还有 ...

  6. Android Multimedia框架总结(六)C++中MediaPlayer的C/S架构

    转载请把头部出处链接和尾部二维码一起转载,本文出自: http://blog.csdn.net/hejjunlin/article/details/52435789 前面几节中,都是通过java层调用 ...

  7. Android Multimedia框架总结(一)MediaPlayer介绍之状态图及生命周期

    请尊重分享成果,转载请注明出处: http://blog.csdn.net/hejjunlin/article/details/52349221 前言:从本篇开始,将进入Multimedia框架,包含 ...

  8. Android Multimedia框架总结(二十一)MediaCodec中创建到start过程(到jni部分)

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53386117 我最近正在参加CS ...

  9. Android Multimedia框架总结(二十)MediaCodec状态周期及Codec与输入/输出Buffer过程(附实例)

    转载请把头部出处链接和尾部二维码一起转载,本文出自逆流的鱼yuiop:http://blog.csdn.net/hejjunlin/article/details/53183718 前言:前面几节都是 ...

随机推荐

  1. 使用REST风格完成MVC前后端分离

    一个具有REST风格项目的基本特征: 具有统一响应结构 前后台数据流转机制(HTTP消息与Java对象的互相转化机制) 统一的异常处理机制 参数验证机制 Cors跨域请求机制 鉴权机制 一:统一响应结 ...

  2. ASP.NET MVC5 使用NPOI导出ExceL 返回浏览器下载

    一,什么是NPOI 该项目是位于http://poi.apache.org/的POI Java项目的.NET版本.POI是一个开源项目,可以帮助您读取/写入xls,doc,ppt文件.它有着广泛的应用 ...

  3. 关于阮大神的es6标准入门第一章

    题记:之前在10月份的时候写过阮大神的es6的第一章,但是由于那段时间项目组的动荡,所以也没有什么后续,导致我现在对es6基本都忘的差不多了,不过,现在换了新公司,最近也没什么任务,所以现在开始重新写 ...

  4. C#之Excel操作

    下面的这几个方法是我在项目中经常用到的,欢迎大家批评指正 读取Excel表中的数据 第一种:功能丰富,速度慢 /// <summary> /// 从Excel读取数据 /// </s ...

  5. hdu 4283 区间dp

    You Are the One Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)T ...

  6. [POI2000] 最长公共子串

    给出几个由小写字母构成的单词,求它们最长的公共子串的长度. 任务 从文件中读入单词 计算最长公共子串的长度 输出结果到文件 输入 文件的第一行是整数 n,1<=n<=5,表示单词的数量.接 ...

  7. [Russian Code Cup 2017 - Finals [Unofficial Mirror]]简要题解

    来自FallDream的博客,未经允许,请勿转载,谢谢. Div1难度+ACM赛制  和几个大佬组队逛了逛 A.给一个大小为n的集合ai(1<=ai<=1000000),要求你构造一个大小 ...

  8. 例10-12 *uva1637(概率dp)

    题意:36张扑克,平分成9摞,两张数字一样的可以拿走,每次随机拿两张,问能拿光的概率. 思路: 直接用搜索,表示出每摞剩余的牌数,然后利用全概率公式即可(P(A) = p(A|b1)*p(b1)+.. ...

  9. SpringBoot跨域问题解决方案

    一.允许全部请求跨域许可的代码: 需要继承WebMvcConfigurerAdapter类 @Configuration public class MyWebAppConfigurer extends ...

  10. Python作业之多级菜单

    作业之多级菜单 菜单实现要求: 1. 列出菜单选择供选择 2. 选择对应内容进入下一级菜单 3. 任何时候都可以选择退出程序或返回上一级菜单 具体代码如下: goods = {'华为':{'A系':{ ...