Google Õë¶ÔÉãÏñÍ·ÒÔ¼°ÊÓÆµ±àÂëÏà¹ØµÄ API£¬¿ØÖÆÁ¦Ò»Ö±·Ç³£²î£¬µ¼Ö²»Í¬³§É̶ÔÕâÁ½¸ö
API µÄʵÏÖÓв»ÉÙ²îÒ죬¶øÇÒ´Ó API µÄÉè¼ÆÀ´¿´£¬Ò»Ö±ÒÔÀ´ÓÅ»¯Ò²Ï൱ÓÐÏÞ£¬ÉõÖÁÓÐÈËÈÏΪÕâÊÇ¡°Android
ÉÏ×îÄÑÓÃµÄ API Ö®Ò»¡±¡£
ÒÔ΢ÐÅΪÀý£¬ÔÚ Android Éè±¸Â¼ÖÆÒ»¸ö 540P µÄ MP4
Îļþ£¬´óÌåÉÏ×ñÑÒÔÏÂÁ÷³Ì£º

ͼ1 Android ÊÓÆµÁ÷±àÂëÁ÷³Ìͼ
´ÓÉãÏñÍ·Êä³öµÄ YUV Ö¡¾¹ýÔ¤´¦ÀíÖ®ºó£¬ËÍÈë±àÂëÆ÷£¬»ñµÃ±àÂëºÃµÄ H264 ÊÓÆµÁ÷¡£
ÉÏÃæÖ»ÊÇÕë¶ÔÊÓÆµÁ÷µÄ±àÂ룬ÁíÍ⻹ÐèÒª¶ÔÒôƵÁ÷µ¥¶ÀÂ¼ÖÆ£¬×îºóÔÙ½«ÊÓÆµÁ÷ºÍÒôƵÁ÷ºÏ³É×îÖÕÊÓÆµ¡£
ÕâÆªÎÄÕÂÖ÷Òª»á¶ÔÊÓÆµÁ÷µÄ±àÂëÖÐÁ½¸ö³£¼ûÎÊÌâ½øÐзÖÎö£º
1.ÊÓÆµ±àÂëÆ÷µÄÑ¡Ôñ£ºÓ²±à or Èí±à£¿
2.ÈçºÎ¶ÔÉãÏñÍ·Êä³öµÄ YUV Ö¡½øÐпìËÙÔ¤´¦Àí£º¾µÏñ¡¢Ëõ·Å¡¢Ðýת£¿
ÊÓÆµ±àÂëÆ÷µÄÑ¡Ôñ
¶ÔÓÚÂ¼ÖÆÊÓÆµµÄÐèÇ󣬲»ÉÙ App ¶¼ÐèÒª¶Ôÿһ֡Êý¾Ý½øÐе¥¶À´¦Àí£¬Òò´ËºÜÉÙ»áÖ±½ÓÓõ½ MediaRecorder
À´Â¼È¡ÊÓÆµ£¬Ò»°ãÀ´Ëµ£¬»áÓÐÁ½¸öÑ¡Ôñ£º
1.MediaCodec
2.FFMpeg+x264/openh264
ÏÂÃæÎÒÃÇÖð¸ö½øÐнâÎö¡£
MediaCodec
MediaCodec ÊÇ API 16 Ö®ºó Google ÍÆ³öµÄÓÃÓÚÒôÊÓÆµ±à½âÂëµÄÒ»Ìׯ«µ×²ãµÄ
API£¬¿ÉÒÔÖ±½ÓÀûÓÃÓ²¼þ¼ÓËÙ½øÐÐÊÓÆµµÄ±à½âÂë¡£µ÷ÓõÄʱºòÐèÒªÏȳõʼ»¯ MediaCodec ×÷ΪÊÓÆµµÄ±àÂëÆ÷£¬È»ºóÖ»ÐèÒª²»Í£´«ÈëÔʼµÄ
YUV Êý¾Ý½øÈë±àÂëÆ÷¾Í¿ÉÒÔÖ±½ÓÊä³ö±àÂëºÃµÄ H.264 Á÷£¬Õû¸ö API Éè¼ÆÄ£ÐÍͬʱ°üº¬ÁËÊäÈë¶ËºÍÊä³ö¶ËµÄÁ½Ìõ¶ÓÁС£

Òò´Ë£¬×÷Ϊ±àÂëÆ÷£¬ÊäÈë¶Ë¶ÓÁдæ·ÅµÄÊÇÔʼ YUV Êý¾Ý£¬Êä³ö¶Ë¶ÓÁÐÊä³öµÄÊDZàÂëºÃµÄ H.264 Á÷£¬×÷Ϊ½âÂëÆ÷Ôò¶ÔÓ¦Ïà·´¡£ÔÚµ÷ÓõÄʱºò£¬MediaCodec
ÌṩÁËͬ²½ºÍÒì²½Á½ÖÖµ÷Ó÷½Ê½£¬µ«ÊÇÒ첽ʹÓà Callback µÄ·½Ê½ÊÇÔÚ API 21 Ö®ºó²Å¼ÓÈëµÄ£¬ÒÔͬ²½µ÷ÓÃΪÀý£¬Ò»°ãÀ´Ëµµ÷Ó÷½Ê½´ó¸ÅÊÇÕâÑù£¨Õª×Ô¹Ù·½Àý×Ó£©£º
MediaCodec
codec = MediaCodec.createByCodecName(name);
codec.configure(format, ¡);
MediaFormat outputFormat = codec.getOutputFormat();
// option B
codec.start();
for (;;) {
int inputBufferId = codec.dequeueInputBuffer(timeoutUs);
if (inputBufferId >= 0) {
ByteBuffer inputBuffer = codec.getInputBuffer(¡);
// fill inputBuffer with valid data
¡
codec.queueInputBuffer(inputBufferId, ¡);
}
int outputBufferId = codec.dequeueOutputBuffer(¡);
if (outputBufferId >= 0) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId);
// option A
// bufferFormat is identical to outputFormat
// outputBuffer is ready to be processed or
rendered.
¡
codec.releaseOutputBuffer(outputBufferId, ¡);
} else if (outputBufferId == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED)
{
// Subsequent data will conform to new format.
// Can ignore if using getOutputFormat(outputBufferId)
outputFormat = codec.getOutputFormat(); // option
B
}
}
codec.stop();
codec.release(); |
¼òµ¥½âÊÍһϣ¬Í¨¹ý getInputBuffers »ñÈ¡ÊäÈë¶ÓÁУ¬È»ºóµ÷Óà dequeueInputBuffer
»ñÈ¡ÊäÈë¶ÓÁпÕÏÐÊý×éϱ꣬עÒâ dequeueOutputBuffer »áÓм¸¸öÌØÊâµÄ·µ»ØÖµ±íʾµ±Ç°±à½âÂë״̬µÄ±ä»¯£¬È»ºóÔÙͨ¹ý
queueInputBuffer °ÑÔʼ YUV Êý¾ÝËÍÈë±àÂëÆ÷£¬¶øÔÚÊä³ö¶ÓÁжËͬÑùͨ¹ý getOutputBuffers
ºÍ dequeueOutputBuffer »ñÈ¡Êä³öµÄ H.264 Á÷£¬´¦ÀíÍêÊä³öÊý¾ÝÖ®ºó£¬ÐèҪͨ¹ý
releaseOutputBuffer °ÑÊä³ö buffer »¹¸øÏµÍ³£¬ÖØÐ·ŵ½Êä³ö¶ÓÁÐÖС£
¹ØÓÚ MediaCodec ¸ü¸´ÔÓµÄʹÓÃÀý×Ó£¬¿ÉÒÔ²ÎÕÕ CTS ²âÊÔÀïÃæµÄʹÓ÷½Ê½£ºEncodeDecodeTest.java¡£
´ÓÉÏÃæÀý×ÓÀ´¿´ MediaCodec µÄÈ·ÊǷdz£ÔʼµÄ API£¬ÓÉÓÚ MediaCodec µ×²ãÖ±½Óµ÷ÓÃÁËÊÖ»úƽ̨Ӳ¼þµÄ±à½âÂëÄÜÁ¦£¬ËùÒÔËٶȷdz£¿ì£¬µ«ÊÇÒòΪ
Google ¶ÔÕû¸ö Android Ó²¼þÉú̬µÄÕÆ¿ØÁ¦·Ç³£Èõ£¬ËùÒÔÕâ¸ö API ÓкܶàÎÊÌ⣺
ÑÕÉ«¸ñʽÎÊÌâ
MediaCodec ÔÚ³õʼ»¯µÄʱºò£¬configure ¹ý³ÌÖÐÐèÒª´«ÈëÒ»¸ö MediaFormat
¶ÔÏ󣬵±×÷Ϊ±àÂëÆ÷ʹÓõÄʱºò£¬ÎÒÃÇÒ»°ãÐèÒªÔÚ MediaFormat ÖÐÖ¸¶¨ÊÓÆµµÄ¿í¸ß¡¢Ö¡ÂÊ¡¢ÂëÂÊ¡¢I
Ö¡¼ä¸ôµÈ»ù±¾ÐÅÏ¢¡£³ý´ËÖ®Í⣬»¹ÓÐÒ»¸öÖØÒªµÄÐÅÏ¢¾ÍÊÇ£¬Ö¸¶¨±àÂëÆ÷½ÓÊÜµÄ YUV Ö¡µÄÑÕÉ«¸ñʽ£¬ÕâÊÇÓÉÓÚ
YUV ¸ù¾ÝÆä²ÉÑù±ÈÀý£¬UV ·ÖÁ¿µÄÅÅÁÐ˳ÐòÓкܶàÖÖ²»Í¬µÄÑÕÉ«¸ñʽ£¬¶ø¶ÔÓÚ Android µÄÉãÏñÍ·ÔÚ
onPreviewFrame Êä³öµÄ YUV Ö¡¸ñʽ£¬Ã»ÓÐÅäÖÃÈκβÎÊýµÄÇé¿öÏ£¬»ù±¾É϶¼ÊÇ NV21
¸ñʽ£¬µ« Google ¶Ô MediaCodec µÄ API ÔÚÉè¼ÆºÍ¹æ·¶µÄʱºò£¬ÏԵúܲ»ºñµÀ£¬¹ýÓÚÌù½ü
Android µÄ HAL ²ãÁË£¬µ¼ÖÂÁË NV21 ¸ñʽ²¢²»ÊÇËùÓлúÆ÷µÄ MediaCodec ¶¼Ö§³ÖÕâÖÖ¸ñʽ×÷Ϊ±àÂëÆ÷µÄÊäÈë¸ñʽ¡£
Òò´Ë£¬ÔÚ³õʼ»¯ MediaCodec µÄʱºò£¬ÎÒÃÇÐèҪͨ¹ý codecInfo.getCapabilitiesForType
À´²éѯ»úÆ÷É쵀 MediaCodec ʵÏÖ¾ßÌåÖ§³ÖÄÄЩ YUV ¸ñʽ×÷ΪÊäÈë¸ñʽ¡£Ò»°ãÀ´Ëµ£¬ÆðÂëÔÚ
4.4+ µÄϵͳÉÏ£¬ÕâÁ½ÖÖ¸ñʽÔڴ󲿷ֻúÆ÷É϶¼ÓÐÖ§³Ö£º
MediaCodecInfo.CodecCapabilities.COLOR_
FormatYUV420Planar
MediaCodecInfo.CodecCapabilities.COLOR_
FormatYUV420SemiPlanar |
Á½ÖÖ¸ñʽ·Ö±ðÊÇ YUV420P ºÍ NV21£¬Èç¹û»úÆ÷ÉÏÖ»Ö§³Ö YUV420P ¸ñʽ£¬ÔòÐèÒªÏȽ«ÉãÏñÍ·Êä³öµÄ
NV21 ¸ñʽÏÈת»»³É YUV420P£¬²ÅÄÜËÍÈë±àÂëÆ÷½øÐбàÂ룬·ñÔò×îÖÕ³öÀ´µÄÊÓÆµ¾Í»á»¨ÆÁ£¬»òÕßÑÕÉ«³öÏÖ´íÂÒ¡£
Õâ¸öËãÊÇÒ»¸ö²»´ó²»Ð¡µÄ¿Ó£¬»ù±¾ÉÏÓà MediaCodec ½øÐÐÊÓÆµ±àÂë¶¼»áÓöÉÏÕâ¸öÎÊÌâ¡£
±àÂëÆ÷Ö§³ÖÌØÐÔÏ൱ÓÐÏÞ
Èç¹ûʹÓà MediaCodec À´±àÂë H.264 ÊÓÆµÁ÷£¬¶ÔÓÚ H.264 ¸ñʽÀ´Ëµ£¬»áÓÐһЩÕë¶ÔѹËõÂÊÒÔ¼°ÂëÂÊÏà¹ØµÄÊÓÆµÖÊÁ¿ÉèÖ㬵äÐ͵ÄÖîÈç
Profile£¨baseline, main, hight£©¡¢Profile Level¡¢Bitrate
mode£¨CBR¡¢CQ¡¢VBR£©£¬ºÏÀíÅäÖÃÕâЩ²ÎÊý¿ÉÒÔÈÃÎÒÃÇÔÚͬµÈµÄÂëÂÊÏ£¬»ñµÃ¸ü¸ßµÄѹËõÂÊ£¬´Ó¶øÌáÉýÊÓÆµµÄÖÊÁ¿£¬Android
Ò²ÌṩÁ˶ÔÓ¦µÄ API ½øÐÐÉèÖ㬿ÉÒÔÉèÖõ½ MediaFormat ÖУº
MediaFormat.KEY_BITRATE_MODE
MediaFormat.KEY_PROFILE
MediaFormat.KEY_LEVEL |
µ«ÎÊÌâÊÇ£¬¶ÔÓÚ Profile¡¢Level¡¢Bitrate mode ÕâЩÉèÖã¬Ôڴ󲿷ÖÊÖ»úÉ϶¼ÊDz»Ö§³ÖµÄ£¬¼´Ê¹ÊÇÉèÖÃÁË×îÖÕÒ²²»»áÉúЧ£¬ÀýÈçÉèÖÃÁË
Profile Ϊ high£¬×îºó³öÀ´µÄÊÓÆµÒÀÈ»»¹»áÊÇ Baseline¡£
Õâ¸öÎÊÌ⣬ÔÚ 7.0 ÒÔϵĻúÆ÷¼¸ºõÊDZØÏֵ쬯äÖÐÒ»¸ö¿ÉÄܵÄÔÒòÊÇ£¬Android ÔÚÔ´Âë²ã¼¶ hardcode
ÁË Profile µÄµÄÉèÖãº
//
XXX
if (h264type.eProfile != OMX_VIDEO_AVCProfileBaseline)
{
ALOGW("Use baseline profile instead of
%d for AVC recording",
h264type.eProfile);
h264type.eProfile = OMX_VIDEO_AVCProfileBaseline;
} |
Android Ö±µ½ 7.0 Ö®ºó²ÅÈ¡ÏûÁËÕâ¶ÎµØ·½µÄ Hardcode¡£
if
(h264type.eProfile == OMX_VIDEO_AVCProfileBaseline)
{
....
} else if (h264type.eProfile == OMX_VIDEO_AVCProfileMain
||
h264type.eProfile == OMX_VIDEO_AVCProfileHigh)
{
.....
} |
Õâ¸öÎÊÌâ¿ÉÒÔ˵¼ä½Óµ¼ÖÂÁË MediaCodec ±àÂë³öÀ´µÄÊÓÆµÖÊÁ¿Æ«µÍ£¬Í¬µÈÂëÂÊÏ£¬ÄÑÒÔ»ñµÃ¸úÈí±àÂëÉõÖÁ
iOS ÄÇÑùµÄÊÓÆµÖÊÁ¿¡£
16 λ¶ÔÆëÒªÇó
Ç°ÃæËµµ½£¬MediaCodec Õâ¸ö API ÔÚÉè¼ÆµÄʱºò£¬¹ýÓÚÌù½ü HAL ²ã£¬ÕâÔںܶà SoC
µÄʵÏÖÉÏ£¬ÊÇÖ±½Ó°Ñ´«Èë MediaCodec µÄ buffer£¬ÔÚ²»¾¹ýÈκÎǰÖô¦ÀíµÄÇé¿öϾÍÖ±½ÓËÍÈëÁË
Soc ÖС£¶øÔÚ±àÂë H264 ÊÓÆµÁ÷µÄʱºò£¬ÓÉÓÚ H264 µÄ±àÂë¿é´óСһ°ãÊÇ 16x16£¬ÓÚÊÇÔÚÒ»¿ªÊ¼ÉèÖÃÊÓÆµ¿í¸ßµÄʱºò£¬Èç¹ûÉèÖÃÁËÒ»¸öûÓÐ¶ÔÆë
16 µÄ´óС£¬ÀýÈç 960x540£¬ÔÚijЩ CPU ÉÏ£¬×îÖÕ±àÂë³öÀ´µÄÊÓÆµ¾Í»áÖ±½Ó»¨ÆÁ¡£
ºÜÃ÷ÏÔÕ⻹ÊÇÒòΪ³§ÉÌÔÚʵÏÖÕâ¸ö API µÄʱºò£¬¶Ô´«ÈëµÄÊý¾ÝȱÉÙУÑéÒÔ¼°Ç°Öô¦Àíµ¼Öµġ£Ä¿Ç°À´¿´£¬»ªÎª¡¢ÈýÐǵÄ
SoC ³öÏÖÕâ¸öÎÊÌâ»á±È½ÏƵ·±£¬ÆäËû³§É̵ÄһЩÔçÆÚ Soc Ò²ÓÐÕâÖÖÎÊÌ⣬һ°ãÀ´Ëµ½â¾ö·½·¨»¹ÊÇÔÚÉèÖÃÊÓÆµ¿í¸ßµÄʱºò£¬Í³Ò»ÉèÖÃ³É¶ÔÆë
16 λ¾ÍºÃÁË¡£
FFMpeg+x264/openh264
³ýÁËʹÓà MediaCodec ½øÐбàÂëÖ®Í⣬ÁíÍâÒ»ÖֱȽÏÁ÷Ðеķ½°¸¾ÍÊÇʹÓà FFmpeg + x264/OpenH264
½øÐÐÈí±àÂ룬FFmpeg ÊÊÓÃÓÚһЩÊÓÆµÖ¡µÄÔ¤´¦Àí¡£ÕâÀïÖ÷ÒªÊÇʹÓà x264/OpenH264 ×÷ΪÊÓÆµµÄ±àÂëÆ÷¡£
x264 »ù±¾Éϱ»ÈÏΪÊǵ±½ñÊÐÃæÉÏ×î¿ìµÄÉÌÓÃÊÓÆµ±àÂëÆ÷£¬¶øÇÒ»ù±¾ÉÏËùÓÐ H264 µÄÌØÐÔ¶¼Ö§³Ö£¬Í¨¹ýºÏÀíÅäÖø÷ÖÖ²ÎÊý»¹ÊÇÄܹ»µÃµ½½ÏºÃµÄѹËõÂʺͱàÂëËٶȵģ¬ÏÞÓÚÆª·ù£¬ÕâÀï²»ÔÙ²ûÊö
H.264 µÄ²ÎÊýÅäÖá£
OpenH264 ÔòÊÇÓÉ˼¿Æ¿ªÔ´µÄÁíÍâÒ»¸ö H264 ±àÂëÆ÷£¬ÏîÄ¿ÔÚ 2013 Ä꿪Դ£¬¶Ô±ÈÆð x264
À´ËµÂÔÏÔÄêÇᣬ²»¹ýÓÉÓÚ˼¿ÆÖ§¸¶ÂòÁË H.264 µÄÄê¶ÈרÀû·Ñ£¬ËùÒÔ¶ÔÓÚÍⲿÓû§À´Ëµ£¬Ï൱ÓÚ¿ÉÒÔÖ±½ÓÃâ·ÑʹÓÃÁË¡£ÁíÍ⣬firefox
Ö±½ÓÄÚÖÃÁË OpenH264£¬×÷ΪÆäÔÚ WebRTC ÖеÄÊÓÆµ±à½âÂëÆ÷ʹÓá£
µ«¶Ô±ÈÆð x264£¬OpenH264 ÔÚ H264 ¸ß¼¶ÌØÐÔµÄÖ§³Ö±È½Ï²î£º
Profile Ö»Ö§³Öµ½ baseline£¬level 5.2£»
¶àÏ̱߳àÂëÖ»Ö§³Ö slice based£¬²»Ö§³Ö frame based
µÄ¶àÏ̱߳àÂë¡£
´Ó±àÂëЧÂÊÉÏÀ´¿´£¬OpenH264 µÄËÙ¶ÈÒ²²¢²»»á±È x264 ¿ì£¬²»¹ýÆä×î´óµÄºÃ´¦£¬»¹ÊÇÄܹ»Ö±½ÓÃâ·ÑʹÓá£
ÈíÓ²±à¶Ô±È
´ÓÉÏÃæµÄ·ÖÎöÀ´¿´£¬Ó²±àµÄºÃ´¦Ö÷ÒªÔÚÓÚËٶȿ죬¶øÇÒϵͳ×Ô´ø£¬²»ÐèÒªÒýÈëÍⲿµÄ¿â£¬µ«ÊÇÌØÐÔÖ§³ÖÓÐÏÞ£¬¶øÇÒÓ²±àµÄѹËõÂÊÒ»°ãÆ«µÍ¡£¶ÔÓÚÈí±àÂëÀ´Ëµ£¬ËäÈ»ËٶȽÏÂý£¬µ«ÊÇѹËõÂʱȽϸߣ¬¶øÇÒÖ§³ÖµÄ
H264 ÌØÐÔÒ²»á±ÈÓ²±àÂë¶àºÜ¶à£¬Ïà¶ÔÀ´Ëµ±È½Ï¿É¿Ø¡£¾Í¿ÉÓÃÐÔ¶øÑÔ£¬ÔÚ 4.4+µÄϵͳÉÏ£¬MediaCodec
µÄ¿ÉÓÃÐÔÊÇÄܹ»»ù±¾±£Ö¤µÄ£¬µ«ÊDz»Í¬µÈ¼¶»úÆ÷µÄ±àÂëÆ÷ÄÜÁ¦»áÓв»ÉÙ²î±ð£¬½¨Òé¿ÉÒÔ¸ù¾Ý»úÆ÷µÄÅäÖã¬Ñ¡Ôñ²»Í¬µÄ±àÂëÆ÷ÅäÖá£
YUV Ö¡µÄÔ¤´¦Àí
¸ù¾Ý×ʼ¸ø³öµÄÁ÷³Ì£¬ÔÚËÍÈë±àÂëÆ÷֮ǰ£¬ÎÒÃÇÐèÒªÏȶÔÉãÏñÍ·Êä³öµÄ YUV Ö¡½øÐÐһЩǰÖô¦Àí¡£
Ëõ·Å
Èç¹ûÉèÖÃÁË Camera µÄÔ¤ÀÀ´óСΪ 1080P£¬ÔÚ onPreviewFrame ÖÐÊä³öµÄ YUV
Ö¡Ö±½Ó¾ÍÊÇ 1920x1080 µÄ´óС£¬Èç¹ûÐèÒª±àÂë¸úÕâ¸ö´óС²»Ò»ÑùµÄÊÓÆµ£¬ÎÒÃǾÍÐèÒªÔÚÂ¼ÖÆµÄ¹ý³ÌÖУ¬ÊµÊ±µÄ¶Ô
YUV Ö¡½øÐÐËõ·Å¡£
ÒÔ΢ÐÅΪÀý£¬ÉãÏñÍ·Ô¤ÀÀ 1080P µÄÊý¾Ý£¬ÐèÒª±àÂë 960x540 ´óСµÄÊÓÆµ¡£
×îΪ³£¼ûµÄ×ö·¨ÊÇʹÓà FFmpeg µÄ swsscale º¯Êý½øÐÐÖ±½ÓËõ·Å£¬Ð§¹û/ÐÔÄܱȽϺõÄÒ»°ãÊÇÑ¡Ôñ
SWSFAST_BILINEAR Ëã·¨£º
mScaleYuvCtxPtr
= sws_getContext(
srcWidth,
srcHeight,
AV_PIX_FMT_NV21,
dstWidth,
dstHeight,
AV_PIX_FMT_NV21,
SWS_FAST_BILINEAR, NULL, NULL, NULL);
sws_scale(mScaleYuvCtxPtr,
(const uint8_t* const *) srcAvPicture->data,
srcAvPicture->linesize, 0, srcHeight,
dstAvPicture->data, dstAvPicture->linesize); |
ÔÚ Nexus 6P ÉÏ£¬Ö±½ÓʹÓà FFmpeg À´½øÐÐËõ·ÅµÄʱ¼ä»ù±¾É϶¼ÐèÒª 40ms+£¬¶ÔÓÚÎÒÃÇÐèÒªÂ¼ÖÆ
30fps µÄÀ´Ëµ£¬Ã¿Ö¡´¦Àíʱ¼ä×î¶à¾Í 30ms£¬Èç¹û¹âÊÇËõ·Å¾ÍÏûºÄÁËÈç´Ë¶àµÄʱ¼ä£¬»ù±¾ÉÏÂ¼ÖÆ³öÀ´µÄÊÓÆµÖ»ÄÜÔÚ
15fps ÉÏÏÂÁË¡£
ºÜÃ÷ÏÔ£¬Ö±½ÓʹÓà FFmpeg ½øÐÐËõ·ÅʵÔÚÌ«ÂýÁË£¬²»µÃ²»Ëµ swsscale
ÔÚ FFmpeg ÀïÃæ²»ÊÊÓ᣾¶Ô±ÈÁ˼¸ÖÖÒµ½ç³£ÓõÄËã·¨Ö®ºó£¬ÎÒÃÇ×îºó¿¼ÂÇʹÓÿìËÙËõ·ÅµÄËã·¨£¬Èçͼ
3 Ëùʾ¡£

ÎÒÃÇÑ¡ÔñÒ»ÖÖ½Ð×ö¾Ö²¿¾ùÖµµÄËã·¨£¬Ç°ºóÁ½ÐÐËĸöÁÙ½üµãËã³ö×îÖÕͼƬµÄËĸöÏñËØµã£¬¶ÔÓÚԴͼƬµÄÿÐÐÏñËØ£¬ÎÒÃÇ¿ÉÒÔʹÓÃ
Neon Ö±½ÓʵÏÖ£¬ÒÔËõ·Å Y ·ÖÁ¿ÎªÀý£º
const
uint8* src_next = src_ptr + src_stride;
asm volatile (
"1: \n"
"vld4.8 {d0, d1, d2, d3}, [%0]! \n"
"vld4.8 {d4, d5, d6, d7}, [%1]! \n"
"subs %3, %3, #16 \n" // 16 processed
per loop
"vrhadd.u8 d0, d0, d1 \n"
"vrhadd.u8 d4, d4, d5 \n"
"vrhadd.u8 d0, d0, d4 \n"
"vrhadd.u8 d2, d2, d3 \n"
"vrhadd.u8 d6, d6, d7 \n"
"vrhadd.u8 d2, d2, d6 \n"
"vst2.8 {d0, d2}, [%2]! \n" // store
odd pixels
"bgt 1b \n"
: "+r"(src_ptr), // %0
"+r"(src_next), // %1
"+r"(dst), // %2
"+r"(dst_width) // %3
:
: "q0", "q1", "q2",
"q3" // Clobber List
); |
ÉÏÃæÊ¹ÓÃµÄ Neon Ö¸Áîÿ´ÎÖ»ÄܶÁÈ¡ºÍ´æ´¢ 8 »òÕß 16 λµÄÊý¾Ý£¬¶ÔÓÚ¶à³öÀ´µÄÊý¾Ý£¬Ö»ÐèÒªÓÃͬÑùµÄËã·¨¸Ä³ÉÓÃ
C ÓïÑÔʵÏÖ¼´¿É¡£
ÔÚʹÓÃÉÏÊöµÄËã·¨ÓÅ»¯Ö®ºó£¬½øÐÐÿ֡Ëõ·Å£¬ÔÚ Nexus 6P ÉÏ£¬Ö»ÐèÒª²»µ½ 5ms ¾ÍÄÜÍê³ÉÁË£¬¶ø¶ÔÓÚËõ·ÅÖÊÁ¿À´Ëµ£¬FFmpeg
µÄ SWSFASTBILINEAR Ëã·¨ºÍÉÏÊöËã·¨Ëõ·Å³öÀ´µÄͼƬ½øÐжԱȣ¬·åÖµÐÅÔë±È£¨psnr£©Ôڴ󲿷ֳ¡¾°Ï´ó¸ÅÔÚ
38-40 ×óÓÒ£¬ÖÊÁ¿Ò²×ã¹»ºÃ¡£
Ðýת
ÔÚ Android »úÆ÷ÉÏ£¬ÓÉÓÚÉãÏñÍ·°²×°½Ç¶È²»Í¬£¬onPreviewFrame ³öÀ´µÄ YUV Ö¡Ò»°ã¶¼ÊÇÐýתÁË
90 ¶È»òÕß 270 ¶È£¬Èç¹û×îÖÕÊÓÆµÊÇÒªÊúÅĵģ¬ÄÇÒ»°ãÀ´ËµÐèÒª°Ñ YUV Ö¡½øÐÐÐýת¡£
¶ÔÓÚÐýתµÄËã·¨£¬Èç¹ûÊÇ´¿ C ʵÏֵĴúÂ룬һ°ãÀ´ËµÊǸö O£¨n2 £©¸´ÔӶȵÄËã·¨£¬Èç¹ûÊÇÐýת 960x540
µÄ YUV Ö¡Êý¾Ý£¬ÔÚ Nexus 6P ÉÏ£¬Ã¿Ö¡ÐýתҲÐèÒª 30ms+£¬ÕâÏÔȻҲÊDz»ÄܽÓÊܵġ£
ÔÚÕâÀïÎÒÃÇ»»¸ö˼·£¬Äܲ»Äܲ»¶Ô YUV Ö¡½øÐÐÐýת£¿ÏÔµ±È»ÊÇ¿ÉÒԵġ£
ÊÂʵÉÏÔÚ MP4 Îļþ¸ñʽµÄÍ·²¿£¬ÎÒÃÇ¿ÉÒÔÖ¸¶¨Ò»¸öÐýת¾ØÕ󣬾ßÌåÀ´ËµÊÇÔÚ moov.trak.tkhd
box ÀïÃæÖ¸¶¨£¬ÊÓÆµ²¥·ÅÆ÷ÔÚ²¥·ÅÊÓÆµµÄʱºò£¬»á¶ÁÈ¡ÕâÀïµÄ¾ØÕóÐÅÏ¢£¬´Ó¶ø¾ö¶¨ÊÓÆµ±¾ÉíµÄÐýת½Ç¶È¡¢Î»ÒÆ¡¢Ëõ·ÅµÈ£¬¾ßÌå¿ÉÒԲο¼Æ»¹ûµÄÎĵµ¡£
ͨ¹ý FFmpeg£¬ÎÒÃÇ¿ÉÒÔºÜÇáËɵĸøºÏ³ÉÖ®ºóµÄ mp4 Îļþ´òÉÏÕâ¸öÐýת½Ç¶È£º
char
rotateStr[1024];
sprintf(rotateStr, "%d", rotate);
av_dict_set(&out_stream->metadata, "rotate",
rotateStr, 0); |
ÓÚÊÇ¿ÉÒÔÔÚÂ¼ÖÆµÄʱºòÊ¡ÏÂÒ»´ó±ÊÐýתµÄ¿ªÏú¡£
¾µÏñ
ÔÚʹÓÃǰÖÃÉãÏñÍ·ÅÄÉãµÄʱºò£¬Èç¹û²»¶Ô YUV Ö¡½øÐд¦Àí£¬ÄÇôֱ½ÓÅijöÀ´µÄÊÓÆµÊǻ᾵Ïñ·×ªµÄ£¬ÕâÀïÔÀí¾Í¸úÕÕ¾µ×ÓÒ»Ñù£¬´ÓǰÖÃÉãÏñÍ··½ÏòÄóöÀ´µÄ
YUV Ö¡¸ÕºÃÊÇ·´µÄ£¬µ«ÓÐЩʱºòÅijöÀ´µÄ¾µÏñÊÓÆµ¿ÉÄܲ»ºÏÎÒÃǵÄÐèÇó£¬Òò´ËÕâ¸öʱºòÎÒÃǾÍÐèÒª¶Ô YUV
Ö¡½øÐоµÏñ·×ª¡£
µ«ÓÉÓÚÉãÏñÍ·°²×°½Ç¶ÈÒ»°ãÊÇ 90 ¶È»òÕß 270 ¶È£¬ËùÒÔʵ¼ÊÉÏÔÉúµÄ YUV Ö¡ÊÇˮƽ·×ª¹ýÀ´µÄ£¬Òò´Ë×ö¾µÏñ·×ªµÄʱºò£¬Ö»ÐèÒª¸ÕºÃÒÔÖмäΪÖÐÖᣬ·Ö±ðÉÏϽ»»»Ã¿ÐÐÊý¾Ý¼´¿É£¬×¢Òâ
Y ¸ú UV Òª·Ö¿ª´¦Àí£¬ÕâÖÖËã·¨Óà Neon ʵÏÖÏ൱¼òµ¥£º
asm
volatile (
"1: \n"
"vld4.8 {d0, d1, d2, d3}, [%2]! \n"
// load 32 from src
"vld4.8 {d4, d5, d6, d7}, [%3]! \n"
// load 32 from dst
"subs %4, %4, #32 \n" // 32 processed
per loop
"vst4.8 {d0, d1, d2, d3}, [%1]! \n"
// store 32 to dst
"vst4.8 {d4, d5, d6, d7}, [%0]! \n"
// store 32 to src
"bgt 1b \n"
: "+r"(src), // %0
"+r"(dst), // %1
"+r"(srcdata), // %2
"+r"(dstdata), // %3
"+r"(count) // %4 // Output registers
: // Input registers
: "cc", "memory", "q0",
"q1", "q2", "q3"
// Clobber List
); |
ͬÑù£¬Ê£ÓàµÄÊý¾ÝÓô¿ C ´úÂëʵÏ־ͺÃÁË£¬ ÔÚ Nexus 6P ÉÏ£¬ÕâÖÖ¾µÏñ·×ªÒ»Ö¡ 1080x1920
YUV Êý¾Ý´ó¸ÅÖ»Òª²»µ½ 5ms¡£
ÔÚ±àÂëºÃ H.264 ÊÓÆµÁ÷Ö®ºó£¬×îÖÕ´¦Àí¾ÍÊǰÑÒôƵÁ÷¸úÊÓÆµÁ÷ºÏÁ÷È»ºó°ü×°µ½ mp4 Îļþ£¬Õⲿ·ÖÎÒÃÇ¿ÉÒÔͨ¹ýϵͳµÄ
MediaMuxer¡¢mp4v2£¬»òÕß FFmpeg À´ÊµÏÖ£¬Õⲿ·Ö±È½Ï¼òµ¥£¬ÔÚÕâÀï¾Í²»ÔÙ²ûÊöÁË¡£
|