文章目录

  • 前言
  • 查看代码重点关注log
  • 1 应用层
    • 1.1 创建
    • 1.2 获取
    • 1.3 设置VideoSource
    • 1.4 设置输出模式
    • 1.5 设置文件名
    • 1.6 设置编码方式
  • 2 获取video codec表——mediaprofile
  • 3 MediaRecorder: prepare
  • 3.1 创建MediaCodecSource(重点看MediaCodec的log)
    • 3.2 Audio
  • 4 MediaRecorder: start
  • 5 小结

前言

从应用层到native层查看mediacodec的创建
后续再看Acodec到omx

查看代码重点关注log

Codec相关:MediaCodec\MediaCodecSource\Acodec\MPEG4Writer\omx
音频数据:AudioSource
视频数据:GraphicBufferSource

1 应用层

以camera代码为例,因为camera使用的是mediarecorder,而audiorecord只能录制pcm数据。

android\packages\apps\SnapdragonCamera\src\com\android\camera\captureModule.java

1.1 创建

mMediaRecorder = new MediaRecorder()

1.2 获取

mMediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);

int audioEncoder = SettingTranslation.getAudioEncoder(mSettingsManager.getValue(SettingsManager.KEY_AUDIO_ENCODER));

1.3 设置VideoSource

mMediaRecorder.setVideoSource(MediaRecorder.VideoSource.SURFACE);
MediaRecorder: setVideoSource(2)
视频数据来源为surface(屏幕显示?),非camera,存疑

1.4 设置输出模式

mMediaRecorder.setOutputFormat(mProfile.fileFormat);
MediaRecorder: setOutputFormat(2)
选择输出模式为mpeg4,目前看起来输出模式只有两种
默认为OUTPUT_FORMAT_THREE_GPP
存疑:为什么输出模式有两种,如何对应encoder,而编码方式中也有mpeg4
解答:这里的mpeg_4和three_gpp都只是文件的存储类型,当前视频的存储格式支持这两种。
而在videoencoder看到的mpeg4是编码类型,同类型的还有h263/h264/h265(hevc)

参考文章:媒体篇 第一章 音频 | 不只是看客


MediaRecorder官方文档导读


1.5 设置文件名

mMediaRecorder.setOutputFile(fileName);

1.6 设置编码方式

mMediaRecorder.setVideoEncoder(mVideoEncoder);
MediaRecorder: setVideoEncoder(2)
选择编码方式为h264

编码格式不同于输出格式,以音频为类比。
视频编码可以分为h264/mpeg4,音频编码为lpcm/aac
视频输出格式常见的是mp4/m4a(outputformat为mpeg4),音频输出格式mp3/wav/amr


视频编码为h264(camera app默认设置)
07-26 22:23:32.636 3772 3772 V MediaRecorder: setVideoEncoder(2)
07-26 23:01:36.513 1129 3967 I OMXMaster: makeComponentInstance(OMX.qcom.video.encoder.avc) in android.hardwar process

视频编码为mpeg4
07-26 23:02:09.983 3772 3772 V MediaRecorder: setVideoEncoder(3)
07-20 23:30:40.325 972 1051 I OMXMaster: makeComponentInstance(OMX.qcom.video.encoder.mpeg4) in android.hardwar process

视频编码为h265
07-26 23:02:28.156 3772 3772 V MediaRecorder: setVideoEncoder(5)
07-26 23:02:28.158 1121 1216 V MPEG4Writer: initInternal
07-26 23:02:28.158 1121 1216 V MediaCodecList: matching ‘OMX.qcom.video.encoder.hevc’
07-26 23:02:28.158 1121 1216 V MediaCodecList: matching ‘c2.android.hevc.encoder’
07-26 23:02:28.158 1121 1216 V ACodec : Now uninitialized
07-26 23:02:28.159 1121 4879 V ACodec : onAllocateComponent
07-26 23:02:28.161 1121 4879 I OMXClient: IOmx service obtained
07-26 23:02:28.162 1129 4672 I OMXMaster: makeComponentInstance(OMX.qcom.video.encoder.hevc) in android.hardwar process


c2.android.hevc.encoder的size不符合

设置h265编码时可选两种编码器,但是最终选择了qcom的硬件编码

1 判断是否是软解码,依据编码器名称是否包含OMX.google.和c2.android.
ps:startsWithIgnoreCase表示不区分大小写

2 判断软解码

以soundrecorder为例,可以看到输出格式为audio/3gpp

以camera mpeg4为例,可以看到输出格式为video/mp4v-es,输入格式为video/raw

以camera h265为例,可以看到输出格式为video/hevc,输入格式为video/raw

2 获取video codec表——mediaprofile

java代码



上层传入encoder类型

根据video_encoder类型,获取编码信息,码率/帧率/宽/高的最大最小值

存疑:sProfiles哪里来的
来源于/vendor/etc/media_profiles_vendor.xml




目前看起来不支持vp8,参见/vendor/etc/media_profiles_vendor.xml

3 MediaRecorder: prepare


3.1 创建MediaCodecSource(重点看MediaCodec的log)

status_t MediaCodecSource::initEncoder() {//1. 根据传入的mimi等信息,查找mediacodeclist中合适的codec名字存入Vector<AString> matchingCodecs中MediaCodecList::findMatchingCodecs(outputMIME.c_str(), true /* encoder */,mFlags,&matchingCodecs);//2. 遍历matchingCodecs,根据名字创建mediacodec//ps:还有一种方式MediaCodec::CreateByType创建mediacodec,或者函数有的时候会用到mEncoder = MediaCodec::CreateByComponentName(mCodecLooper, matchingCodecs[ix]);//3. 打印输出格式ALOGV("output format is '%s'", mOutputFormat->debugString(0).c_str());//4. 配置mediacodecerr = mEncoder->configure();//5. 启动mediacodecerr = mEncoder->start();
}

1 查找匹配的codec名字
输入mime,在MediaCodecList中查找合适的codec名字,存入matches中
mime --> MediaCodecList.matches.name

07-28 03:44:05.130   945  3290 D MediaCodecSource: youkai in MediaCodecSource::initEncoder
07-28 03:44:05.130   945  3290 V MediaCodecList: youkai in MediaCodecList::findMatchingCodecs
07-28 03:44:05.130   945  3290 V MediaCodecList: matching 'OMX.qcom.video.encoder.mpeg4'
07-28 03:44:05.130   945  3290 V MediaCodecList: matching 'c2.android.mpeg4.encoder'
07-28 03:44:05.130   945  3290 V MediaCodecList: matching 'OMX.google.mpeg4.encoder'

至此匹配到三个encoder

07-28 03:44:05.130 945 3290 V MediaCodecList: matching ‘OMX.qcom.video.encoder.mpeg4’
Media_codecs.xml
07-28 03:44:05.130 945 3290 V MediaCodecList: matching ‘c2.android.mpeg4.encoder’
07-28 03:44:05.130 945 3290 V MediaCodecList: matching ‘OMX.google.mpeg4.encoder’
Media_codecs_sw.xml (frameworks\av\media\libstagefright\data)
Size不符合淘汰

2 根据名字创建mediacodec

3 打出输出格式,这个参数是从app传来的

07-28 03:44:05.161   945 15206 V ACodec  : [OMX.qcom.video.encoder.mpeg4] Now Loaded
07-28 03:44:05.163   945  3290 V MediaCodecSource: output format is 'AMessage(what = 0x00000000) = {07-28 03:44:05.163   945  3290 V MediaCodecSource:   string mime = "video/mp4v-es"
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t width = 1920
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t height = 1080
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t stride = 1920
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t slice-height = 1080
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t color-format = 2130708361
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t bitrate = 20000000
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t frame-rate = 30
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t i-frame-interval = 1
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t priority = 0
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t feature-nal-length-bitstream = 1
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t nal-length-in-bytes = 4
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t isNativeRecorder = 1
07-28 03:44:05.163   945  3290 V MediaCodecSource:   int32_t create-input-buffers-suspended = 1
07-28 03:44:05.163   945  3290 V MediaCodecSource: }'
07-28 03:44:05.163   945 15205 I MediaCodec: MediaCodec will operate in async mode
07-28 03:44:05.163   945 15205 V MediaCodec: kWhatConfigure: Old mCrypto: 0x0 (0)
07-28 03:44:05.163   945 15205 V MediaCodec: kWhatConfigure: New mCrypto: 0x0 (0)
07-28 03:44:05.163   945 15205 V MediaCodec: Found 0 pieces of codec specific data.
07-28 03:44:05.163   945 15206 V ACodec  : onConfigureComponent

4 mediacodec的消息机制接受到kWhatComponentConfigured,打印出输入和输出格式

07-28 03:44:05.226   945 15205 V MediaCodec: [OMX.qcom.video.encoder.mpeg4] configured as input format: AMessage(what = 0x00000000) = {07-28 03:44:05.226   945 15205 V MediaCodec:       string mime = "video/raw"
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t stride = 1920
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t slice-height = 1080
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t color-format = 2130708361
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t color-range = 0
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t color-standard = 0
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t color-transfer = 0
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t width = 1920
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t height = 1080
07-28 03:44:05.226   945 15205 V MediaCodec:     }, output format: AMessage(what = 0x00000000) = {07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t bitrate = 20000000
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t max-bitrate = 20000000
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t frame-rate = 30
07-28 03:44:05.226   945 15205 V MediaCodec:       string mime = "video/mp4v-es"
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t width = 1920
07-28 03:44:05.226   945 15205 V MediaCodec:       int32_t height = 1080
07-28 03:44:05.226   945 15205 V MediaCodec:     }
07-28 03:44:05.227   945 15206 V ACodec  : onCreateInputSurface
07-28 03:44:05.227   953  2087 V GraphicBufferSource: GraphicBufferSource

5 接受到GraphicBufferSource传来的创建显示消息kWhatInputSurfaceCreated

07-28 03:44:05.232   945 15205 V MediaCodec: [OMX.qcom.video.encoder.mpeg4] input surface created as input format: AMessage(what = 0x00000000) = {07-28 03:44:05.232   945 15205 V MediaCodec:       string mime = "video/raw"
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t stride = 1920
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t slice-height = 1080
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-format = 2130708361
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-range = 2
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-standard = 1
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-transfer = 3
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t width = 1920
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t height = 1080
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t android._dataspace = 260
07-28 03:44:05.232   945 15205 V MediaCodec:       Buffer android._color-aspects = {07-28 03:44:05.232   945 15205 V MediaCodec:         00000000:  02 00 00 00 01 00 00 00  03 00 00 00 01 00 00 00  ................
07-28 03:44:05.232   945 15205 V MediaCodec:       }
07-28 03:44:05.232   945 15205 V MediaCodec:     }, output format: AMessage(what = 0x00000000) = {07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t bitrate = 20000000
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t max-bitrate = 20000000
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t frame-rate = 30
07-28 03:44:05.232   945 15205 V MediaCodec:       string mime = "video/mp4v-es"
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t width = 1920
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t height = 1080
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-range = 2
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-standard = 1
07-28 03:44:05.232   945 15205 V MediaCodec:       int32_t color-transfer = 3
07-28 03:44:05.232   945 15205 V MediaCodec:     }
07-28 03:44:05.232   945  3290 V MediaCodecSource: setting dataspace 0x104, format 0x22
07-28 03:44:05.232   945 15206 V ACodec  : onStart
07-28 03:44:05.232   953  1026 V GraphicBufferSource: stop

3.2 Audio

07-28 03:44:05.303   945  3290 D MediaCodecSource: youkai in MediaCodecSource::initEncoder
07-28 03:44:05.303   945  3290 V ACodec  : Now uninitialized
07-28 03:44:05.304   945 15212 V ACodec  : onAllocateComponent
07-28 03:44:05.306   945 15212 I OMXClient: IOmx service obtained
07-28 03:44:05.306   714 15211 V AudioFlinger: acquireWakeLock_l() AudioIn_7E status 0
07-28 03:44:05.306   714 15211 D AudioFlinger: updateWakeLockUids_l AudioIn_7E uids:
07-28 03:44:05.306   953  1026 I OMXMaster: makeComponentInstance(OMX.qcom.audio.encoder.aac) in android.hardwar process
07-28 03:44:05.306   714 15211 V AudioFlinger: updateWakeLockUids_l() AudioIn_7E status 0
07-28 03:44:05.308   714 15211 V AudioFlinger: releaseWakeLock_l() AudioIn_7E
07-28 03:44:05.309   714 15211 V AudioFlinger: RecordThread: loop stopping
07-28 03:44:05.314   953  1026 E         :  component init: role = OMX.qcom.audio.encoder.aac
07-28 03:44:05.324     0     0 I aac_in_open: session id 2: NT mode encoder success
07-28 03:44:05.324     0     0 I aac_in_open: session id 2: success
07-28 03:44:05.327   953  1026 W media.codec: Failed to obtain quirks for omx component 'OMX.qcom.audio.encoder.aac' from XML files
07-28 03:44:05.328   945 15212 V ACodec  : [OMX.qcom.audio.encoder.aac] Now Loaded
07-28 03:44:05.329   945  3290 V MediaCodecSource: output format is 'AMessage(what = 0x00000000) = {07-28 03:44:05.329   945  3290 V MediaCodecSource:   string mime = "audio/mp4a-latm"
07-28 03:44:05.329   945  3290 V MediaCodecSource:   int32_t aac-profile = 2
07-28 03:44:05.329   945  3290 V MediaCodecSource:   int32_t max-input-size = 2048
07-28 03:44:05.329   945  3290 V MediaCodecSource:   int32_t channel-count = 2
07-28 03:44:05.329   945  3290 V MediaCodecSource:   int32_t sample-rate = 48000
07-28 03:44:05.329   945  3290 V MediaCodecSource:   int32_t bitrate = 96000
07-28 03:44:05.329   945  3290 V MediaCodecSource:   int32_t priority = 0
07-28 03:44:05.329   945  3290 V MediaCodecSource: }'
07-28 03:44:05.330   945 15212 I MediaCodec: MediaCodec will operate in async mode
07-28 03:44:05.331   945 15212 V MediaCodec: kWhatConfigure: Old mCrypto: 0x0 (0)
07-28 03:44:05.332   945 15212 V MediaCodec: kWhatConfigure: New mCrypto: 0x0 (0)
07-28 03:44:05.332   945 15212 V MediaCodec: Found 0 pieces of codec specific data.
07-28 03:44:05.332   945 15212 V ACodec  : onConfigureComponent07-28 03:44:05.334   945 15212 V MediaCodec: [OMX.qcom.audio.encoder.aac] configured as input format: AMessage(what = 0x00000000) = {07-28 03:44:05.334   945 15212 V MediaCodec:       string mime = "audio/raw"
07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t channel-count = 2
07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t sample-rate = 48000
07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t pcm-encoding = 2
07-28 03:44:05.334   945 15212 V MediaCodec:     }, output format: AMessage(what = 0x00000000) = {07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t bitrate = 96000
07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t max-bitrate = 96000
07-28 03:44:05.334   945 15212 V MediaCodec:       string mime = "audio/mp4a-latm"
07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t channel-count = 2
07-28 03:44:05.334   945 15212 V MediaCodec:       int32_t sample-rate = 48000
07-28 03:44:05.334   945 15212 V MediaCodec:     }
07-28 03:44:05.335   945  3290 V MediaCodecSource: setting dataspace 0x10c10000, format 0x22
07-28 03:44:05.335   945 15212 V ACodec  : onStart07-28 03:44:05.367   945 15212 V MediaCodec: [OMX.qcom.audio.encoder.aac] output format changed to: AMessage(what = 0x00000000) = {07-28 03:44:05.367   945 15212 V MediaCodec:       int32_t bitrate = 96000
07-28 03:44:05.367   945 15212 V MediaCodec:       int32_t max-bitrate = 96000
07-28 03:44:05.367   945 15212 V MediaCodec:       string mime = "audio/mp4a-latm"
07-28 03:44:05.367   945 15212 V MediaCodec:       int32_t channel-count = 2
07-28 03:44:05.367   945 15212 V MediaCodec:       int32_t sample-rate = 48000
07-28 03:44:05.367   945 15212 V MediaCodec:     }
07-28 03:44:05.367   945 15212 V MediaCodec: -- returned buffer timestamp 0 <= 0, ignore it
07-28 03:44:05.367   945 15204 E Utils   : csd0 too small
07-28 03:44:05.367   945 15204 E ExtendedUtils: csd0 too small
07-28 03:44:05.368   945 15212 V ACodec  : [OMX.qcom.audio.encoder.aac] calling fillBuffer 3

4 MediaRecorder: start

07-28 03:44:05.756 14402 14402 V MediaRecorder: start
07-28 03:44:05.756   945  1028 V StagefrightRecorder: start
07-28 03:44:05.756   945  1028 V MPEG4Writer: movie time scale: 1000
07-28 03:44:05.756   945  1028 V MPEG4Writer: muxer starting: mHasMoovBox 1, mHasFileLevelMeta 0
07-28 03:44:05.757   945  1028 I MPEG4Writer: limits: 11065696640/600000000 bytes/us, bit rate: 20096000 bps and the estimated moov size 405120 bytes
07-28 03:44:05.757   945  1028 V MPEG4Writer: startWriterThread
07-28 03:44:05.757   945  1028 V MPEG4Writer: initTrackingProgressStatus
07-28 03:44:05.757   945  1028 I MPEG4Writer: Start time offset: 100000 us
07-28 03:44:05.757   945 15239 V MPEG4Writer: ThreadWrapper: 0xeb153180
07-28 03:44:05.757   945 15239 V MPEG4Writer: threadFunc
07-28 03:44:05.757   945 15239 V MPEG4Writer: findChunkToWrite
07-28 03:44:05.757   945 15239 V MPEG4Writer: Nothing to be written after all
07-28 03:44:05.757   945 15204 I MediaCodecSource: MediaCodecSource (video) starting
07-28 03:44:05.758   945 15204 I MediaCodecSource: MediaCodecSource (video) started
07-28 03:44:05.758   945  1028 V MPEG4Writer: initTrackingProgressStatus
07-28 03:44:05.759   945  1028 I MPEG4Writer: Start time offset: 100000 us
07-28 03:44:05.759   945 15204 I MediaCodecSource: MediaCodecSource (audio) starting
07-28 03:44:05.759   945 15204 V MediaCodecSource: puller (audio) start
07-28 03:44:05.759   953 14820 D GraphicBufferSource: setStartTimeUs: skipFramesBeforeUs=81188109321
07-28 03:44:05.760   953  1026 V GraphicBufferSource: setSuspend=0 at time -1 us
07-28 03:44:05.763   945 15241 V AudioRecord: start(48): sync event 0 trigger session 0

5 小结

本章主要介绍从java的mediarecorder到mediacodec创建流程。

  1. 从app传下来结果关键参数(编码类型)
  2. 经过mediaprofile的过滤,选择出支持的格式
  3. 将mime传给mediacodeclist选择合适的encoder名字
  4. 根据encoder名字创建mediacodec(这里会创建Acodec,然后到omx和MPEG4writer,后续文章介绍)
    mediarecorder的prepare阶段重点创建音视频的encoder,start阶段简单介绍

【mediacodec】MediaRecorder--MediaCodec相关推荐

  1. 【转载】 Android MediaCodec stuff

    原文链接: Android MediaCodec stuff Android MediaCodec stuff Last update: 2016-06-08 Overview Samples FAQ ...

  2. 【Android音视频开发】【015】通过MediaCodec和SurfaceView,对H264数据进行解帧和播放

    功能点 从连续的字节块中,解析分割出多个H264帧数据 通过MediaCodec解码H264帧 通过SurfaceView播放 代码 //H264数据解析package com.easing.comm ...

  3. 【AVD】FFmpeg + MediaCodec 实现 Android 硬件解码,中间有个大坑

    最近在做移动端音视频编解码,首先要实现的是移动端视频的解码功能.纯的 FFmpeg 方法在移动端也能实现,但是效率上的确要慢一些,1080p 的视频还好,但是上到 2k.4k,那个解码速度(以肉眼可见 ...

  4. 【AudioVideo】MediaRecorder概述(21)

    原 Android多媒体框架支持捕获和编码各种常见的音频和视频格式.MediaRecorder如果设备硬件支持,您可以使用这些API. 本文档向您介绍如何使用它MediaRecorder来编写捕获设备 ...

  5. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 配置

    MediaRecorder 录像配置主要涉及输出文件路径.音频来源.视频来源.输出格式.音频编码格式.视频编码格式.比特率.帧率和视频尺寸等. 我们假设视频输入源来自 Camera,Camera2 A ...

  6. 【Android 10 源码】MediaRecorder 录像流程:MediaRecorder 初始化

    MediaRecorder 用于录制音频和视频,录制控制基于一个简单的状态机.下面是典型的使用 camera2 API 录制,需要使用到的 MediaRecorder API. MediaRecord ...

  7. 【翻译】安卓新播放器EXOplayer介绍

    [翻译]安卓新播放器EXOplayer介绍 http://developer.android.com/guide/topics/media/exoplayer.html 前言: Playing vid ...

  8. 【VLC-Android】Mac下编译vlc-android

    前言 突然想整整VLC-Android,然后就下一个玩玩看,这里记录点遇到的问题. 声明 欢迎转载,但请保留文章原始出处:)  博客园:http://www.cnblogs.com 农民伯伯: htt ...

  9. android音视频【十】音频mp3剪切

    人间观察 为了等你,我错过了等我的人. 介绍 Android中在一些短视频的制作app软件上,会有给视频增加背景音乐的功能,而背景音乐/歌曲(一般是mp3)是从服务器上下载后,然后本地解码,往往用户会 ...

最新文章

  1. 电子商务思维导图精品荟萃:电子商务思维导图大全[多图精品收藏]
  2. Opera 发布新技术 Opera Unite
  3. 【计算机系统设计】实践笔记(3)改进数据通路:移位R型指令分析
  4. 机器视觉与Tesseract介绍
  5. 从零开始搭建Ubuntu 环境下的Android 源码开发环境
  6. 微软中国回应关闭实体直营店:中国市场保持正常营运
  7. linux系统挂载NTFS格式文件系统
  8. Unity热更新学习(二) —— ToLua c#与lua的相互调用
  9. bert处理英文的词根处理
  10. GPRS模块SIM900A怎么用
  11. 学习感悟(人脸识别)
  12. win10键盘鼠标怎么使用?(键盘操纵鼠标)
  13. 聚合购物一站式采购平台HTML网站源码
  14. APP+springboot订餐APP 毕业设计源码190711
  15. Day11-软件测试设计之银行储蓄系统
  16. 消费互联网、产业互联网、工业互联网、能源互联网的关键区别是什么?智慧城市、智慧园区、智慧交通、智慧水务、智能电网、智慧工厂中都需要的关键技术是什么?
  17. babylon创建文字
  18. 手机html5游戏内存修改,一种防止游戏被内存修改器修改的方法
  19. 王道数据结构2021年课件PPT分享
  20. Oracle spm

热门文章

  1. 90%的 CTO 都做不好绩效管理
  2. Github上一个优秀的Python学习资源:AwesomePythonResource
  3. 布兰迪斯大学计算机美国大学排名,布兰迪斯大学排名
  4. 第七章 项目招投标与合同管理
  5. 关于微信群、QQ群和其他发布平台
  6. 方法重载在同一个类中,方法名相同,参数不同,可以定义多个同名的方法根据不同的参数,可以调用不同的方法
  7. 机器学习入门之莺尾花训练
  8. Chess.com:象棋社区网站每月访问量达 2.8 亿,年收入在 5000 万至 1 亿之间
  9. 消费者理论:效用函数
  10. 如何使用Win10自带的录屏功能以及如何查找到视频存放的位置