仿微信小视频录制控件

本文为用 MediaRecorder 录制小视频的控件,可以设置视频录制的时间、空间大小、初始时是否打开摄像头等。 此控件为组合控件,继承自 LinearLayout ,为防止出错,需实现 android.media.MediaRecorder.OnErrorListener 接口。

1. [文件] MovieRecorderView.java ~ 9KB

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

217

218

219

220

221

222

223

224

225

226

227

228

229

230

231

232

233

234

235

236

237

238

239

240

241

242

243

244

245

246

247

248

249

250

251

252

253

254

255

256

257

258

259

260

261

262

263

264

265

266

267

268

269

270

271

272

273

274

275

276

277

278

279

280

281

282

283

284

285

286

287

288

289

290

291

292

293

294

295

296

297

298

299

300

301

302

303

304

305

306

307

308

309

310

311

312

313

314

315

316

317

318

319

320

321

322

323

324

325

326

327

328

329

330

331

332

333

334

335

336

337

338

339

340

341

342

343

344

345

346

347

348

349

350

351

352

353

354

355

356

import

java.io.File;

import

java.io.IOException;

import

java.util.Timer;

import

java.util.TimerTask;

import

android.content.Context;

import

android.content.res.TypedArray;

import

android.hardware.Camera;

import

android.hardware.Camera.Parameters;

import

android.media.MediaRecorder;

import

android.media.MediaRecorder.AudioEncoder;

import

android.media.MediaRecorder.AudioSource;

import

android.media.MediaRecorder.OnErrorListener;

import

android.media.MediaRecorder.OutputFormat;

import

android.media.MediaRecorder.VideoEncoder;

import

android.media.MediaRecorder.VideoSource;

import

android.util.AttributeSet;

import

android.view.LayoutInflater;

import

android.view.SurfaceHolder;

import

android.view.SurfaceHolder.Callback;

import

android.view.SurfaceView;

import

android.widget.LinearLayout;

import

android.widget.ProgressBar;

import

com.contron.dgyj.R;

import

com.contron.dgyj.common.Globals;

import

com.contron.dgyj.im.ImGlobal;

import

com.lidroid.xutils.util.LogUtils;

/**

 *
视频播放控件

 *

 *
@author liuyinjun

 *

 *
@date 2015-2-5

 */

public

class

MovieRecorderView
extends

LinearLayout
implements

OnErrorListener {

    private

SurfaceView mSurfaceView;

    private

SurfaceHolder mSurfaceHolder;

    private

ProgressBar mProgressBar;

    private

MediaRecorder mMediaRecorder;

    private

Camera mCamera;

    private

Timer mTimer;
//
计时器

    private

OnRecordFinishListener mOnRecordFinishListener;
//
录制完成回调接口

    private

int

mWidth;
//
视频分辨率宽度

    private

int

mHeight;
//
视频分辨率高度

    private

boolean

isOpenCamera;
//
是否一开始就打开摄像头

    private

int

mRecordMaxTime;
//
一次拍摄最长时间

    private

int

mTimeCount;
//
时间计数

    private

File mVecordFile =
null;//
文件

    public

MovieRecorderView(Context context) {

        this(context,
null);

    }

    public

MovieRecorderView(Context context, AttributeSet attrs) {

        this(context,
attrs,
0);

    }

    public

MovieRecorderView(Context context, AttributeSet attrs,
int

defStyle) {

        super(context,
attrs, defStyle);

        TypedArray
a = context.obtainStyledAttributes(attrs, R.styleable.MovieRecorderView, defStyle,
0);

        mWidth
= a.getInteger(R.styleable.MovieRecorderView_width,
320);//
默认320

        mHeight
= a.getInteger(R.styleable.MovieRecorderView_height,
240);//
默认240

        isOpenCamera
= a.getBoolean(R.styleable.MovieRecorderView_is_open_camera,
true);//
默认打开

        mRecordMaxTime
= a.getInteger(R.styleable.MovieRecorderView_record_max_time,
10);//
默认为10

        LayoutInflater.from(context).inflate(R.layout.movie_recorder_view,
this);

        mSurfaceView
= (SurfaceView) findViewById(R.id.surfaceview);

        mProgressBar
= (ProgressBar) findViewById(R.id.progressBar);

        mProgressBar.setMax(mRecordMaxTime);//
设置进度条最大量

        mSurfaceHolder
= mSurfaceView.getHolder();

        mSurfaceHolder.addCallback(new

CustomCallBack());

        mSurfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        a.recycle();

    }

    /**

     *

     *
@author liuyinjun

     *

     *
@date 2015-2-5

     */

    private

class

CustomCallBack
implements

Callback {

        @Override

        public

void

surfaceCreated(SurfaceHolder holder) {

            if

(!isOpenCamera)

                return;

            try

{

                initCamera();

            }
catch

(IOException e) {

                //
TODO Auto-generated catch block

                e.printStackTrace();

            }

        }

        @Override

        public

void

surfaceChanged(SurfaceHolder holder,
int

format,
int

width,
int

height) {

        }

        @Override

        public

void

surfaceDestroyed(SurfaceHolder holder) {

            if

(!isOpenCamera)

                return;

            freeCameraResource();

        }

    }

    /**

     *
初始化摄像头

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     *
@throws IOException

     */

    private

void

initCamera()
throws

IOException {

        if

(mCamera !=
null)
{

            freeCameraResource();

        }

        try

{

            mCamera
= Camera.open();

        }
catch

(Exception e) {

            e.printStackTrace();

            freeCameraResource();

        }

        if

(mCamera ==
null)

            return;

        setCameraParams();

        mCamera.setDisplayOrientation(90);

        mCamera.setPreviewDisplay(mSurfaceHolder);

        mCamera.startPreview();

        mCamera.unlock();

    }

    /**

     *
设置摄像头为竖屏

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     */

    private

void

setCameraParams() {

        if

(mCamera !=
null)
{

            Parameters
params = mCamera.getParameters();

            params.set("orientation",
"portrait");

            mCamera.setParameters(params);

        }

    }

    /**

     *
释放摄像头资源

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     */

    private

void

freeCameraResource() {

        if

(mCamera !=
null)
{

            mCamera.setPreviewCallback(null);

            mCamera.stopPreview();

            mCamera.lock();

            mCamera.release();

            mCamera
=
null;

        }

    }

    private

void

createRecordDir() {

        File
sampleDir =
new

File(Environment.getExternalStorageDirectory() + File.separator +
"im/video/");

        if

(!sampleDir.exists()) {

            sampleDir.mkdirs();

        }

        File
vecordDir = sampleDir;

        //
创建文件

        try

{

            mVecordFile
= File.createTempFile(
"recording",
".mp4",
vecordDir);
//mp4格式

            LogUtils.i(mVecordFile.getAbsolutePath());

        }
catch

(IOException e) {

        }

    }

    /**

     *
初始化

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     *
@throws IOException

     */

    private

void

initRecord()
throws

IOException {

        mMediaRecorder
=
new

MediaRecorder();

        mMediaRecorder.reset();

        if

(mCamera !=
null)

            mMediaRecorder.setCamera(mCamera);

        mMediaRecorder.setOnErrorListener(this);

        mMediaRecorder.setPreviewDisplay(mSurfaceHolder.getSurface());

        mMediaRecorder.setVideoSource(VideoSource.CAMERA);//
视频源

        mMediaRecorder.setAudioSource(AudioSource.MIC);//
音频源

        mMediaRecorder.setOutputFormat(OutputFormat.MPEG_4);//
视频输出格式

        mMediaRecorder.setAudioEncoder(AudioEncoder.AMR_NB);//
音频格式

        mMediaRecorder.setVideoSize(mWidth,
mHeight);
//
设置分辨率:

        //
mMediaRecorder.setVideoFrameRate(16);// 这个我把它去掉了,感觉没什么用

        mMediaRecorder.setVideoEncodingBitRate(1

*
1024

*
512);//
设置帧频率,然后就清晰了

        mMediaRecorder.setOrientationHint(90);//
输出旋转90度,保持竖屏录制

        mMediaRecorder.setVideoEncoder(VideoEncoder.MPEG_4_SP);//
视频录制格式

        //
mediaRecorder.setMaxDuration(Constant.MAXVEDIOTIME * 1000);

        mMediaRecorder.setOutputFile(mVecordFile.getAbsolutePath());

        mMediaRecorder.prepare();

        try

{

            mMediaRecorder.start();

        }
catch

(IllegalStateException e) {

            e.printStackTrace();

        }
catch

(RuntimeException e) {

            e.printStackTrace();

        }
catch

(Exception e) {

            e.printStackTrace();

        }

    }

    /**

     *
开始录制视频

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     *
@param fileName

     *           
视频储存位置

     *
@param onRecordFinishListener

     *           
达到指定时间之后回调接口

     */

    public

void

record(
final

OnRecordFinishListener onRecordFinishListener) {

        this.mOnRecordFinishListener
= onRecordFinishListener;

        createRecordDir();

        try

{

            if

(!isOpenCamera)
//
如果未打开摄像头,则打开

                initCamera();

            initRecord();

            mTimeCount
=
0;//
时间计数器重新赋值

            mTimer
=
new

Timer();

            mTimer.schedule(new

TimerTask() {

                @Override

                public

void

run() {

                    //
TODO Auto-generated method stub

                    mTimeCount++;

                    mProgressBar.setProgress(mTimeCount);//
设置进度条

                    if

(mTimeCount == mRecordMaxTime) {
//
达到指定时间,停止拍摄

                        stop();

                        if

(mOnRecordFinishListener !=
null)

                            mOnRecordFinishListener.onRecordFinish();

                    }

                }

            },
0,
1000);

        }
catch

(IOException e) {

            e.printStackTrace();

        }

    }

    /**

     *
停止拍摄

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     */

    public

void

stop() {

        stopRecord();

        releaseRecord();

        freeCameraResource();

    }

    /**

     *
停止录制

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     */

    public

void

stopRecord() {

        mProgressBar.setProgress(0);

        if

(mTimer !=
null)

            mTimer.cancel();

        if

(mMediaRecorder !=
null)
{

            //
设置后不会崩

            mMediaRecorder.setOnErrorListener(null);

            mMediaRecorder.setPreviewDisplay(null);

            try

{

                mMediaRecorder.stop();

            }
catch

(IllegalStateException e) {

                e.printStackTrace();

            }
catch

(RuntimeException e) {

                e.printStackTrace();

            }
catch

(Exception e) {

                e.printStackTrace();

            }

        }

    }

    /**

     *
释放资源

     *

     *
@author liuyinjun

     *
@date 2015-2-5

     */

    private

void

releaseRecord() {

        if

(mMediaRecorder !=
null)
{

            mMediaRecorder.setOnErrorListener(null);

            try

{

                mMediaRecorder.release();

            }
catch

(IllegalStateException e) {

                e.printStackTrace();

            }
catch

(Exception e) {

                e.printStackTrace();

            }

        }

        mMediaRecorder
=
null;

    }

    public

int

getTimeCount() {

        return

mTimeCount;

    }

    /**

     *
@return the mVecordFile

     */

    public

File getmVecordFile() {

        return

mVecordFile;

    }

    /**

     *
录制完成回调接口

     *

     *
@author liuyinjun

     *

     *
@date 2015-2-5

     */

    public

interface

OnRecordFinishListener {

        public

void

onRecordFinish();

    }

    @Override

    public

void

onError(MediaRecorder mr,
int

what,
int

extra) {

        try

{

            if

(mr !=
null)

                mr.reset();

        }
catch

(IllegalStateException e) {

            e.printStackTrace();

        }
catch

(Exception e) {

            e.printStackTrace();

        }

    }

}

2. [文件] movie_recorder_view.xml ~ 747B

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

<?xml

version
="1.0"

encoding
="utf-8"?>

<LinearLayout

xmlns:android
="http://schemas.android.com/apk/res/android"

    xmlns:tools="http://schemas.android.com/tools"

    android:layout_width="match_parent"

    android:layout_height="match_parent"

    android:background="@android:color/background_dark"

    android:orientation="vertical">

    <SurfaceView

         android:id="@+id/surfaceview"

         android:layout_width="fill_parent"

         android:layout_height="0dp"

         android:layout_weight="1"

          />

    <ProgressBar

        android:id="@+id/progressBar"

        style="?android:attr/progressBarStyleHorizontal"

        android:layout_width="match_parent"

        android:layout_height="2dp"

        />

    

</LinearLayout>

有问题,欢迎交流与学习!

时间: 2024-08-11 08:20:53

仿微信小视频录制控件的相关文章

Android 微信小视频录制功能实现

目录 开发之前 开发环境 相关知识点 开始开发 案例预览 案例分析 搭建布局 视频预览的实现 自定义双向缩减的进度条 录制事件的处理 长按录制 抬起保存 上滑取消 双击放大(变焦) 实现视频的录制 实现视频的停止 完整代码 总结 开发之前 这几天接触了一下和视频相关的控件, 所以, 继之前的微信摇一摇, 我想到了来实现一下微信小视频录制的功能, 它的功能点比较多, 我每天都抽出点时间来写写, 说实话, 有些东西还是比较费劲, 希望大家认真看看, 说得不对的地方还请大家在评论中指正. 废话不多说,

完美解决微信video视频隐藏控件和内联播放问题

众所周知,微信浏览器下的html5视频播放兼容性一直是很头疼的问题,其中两个最主要的问题是隐藏播放控件和内联播放,在ios系统下这两个功能还比较好实现,重点是在android端,今天就给大家提供一个比较特殊的方法. 先看一下html代码格式: <div class="videoBox"> <i class="fa fa-play-circle-o"></i> <video id="video" x5-vi

仿微信小视频播放控件

变量如下: private SurfaceHolder mSurfaceHolder; private MediaPlayer mPlayer; 构造函数内获取 SurfaceHolder,并设置回调接口 Callback: public MoviePlayerView(Context context, AttributeSet attrs, int defStyle) {   super(context, attrs, defStyle);      mSurfaceHolder = this

iOS微信小视频优化心得

小视频是微信6.0版本重大功能之一,在开发过程中遇到不少问题.本文先叙述小视频的产品需求,介绍了几个实现方案,分析每个方案的优缺点,最后总结出最优的解决方案. 小视频播放需求 可以同时播放多个视频 用户操作界面时视频可以继续播放 播放时不能卡住界面,视频滑进界面内后要立即播放 视频在列表内播放是静音播放,点击放大是有声播放 小视频播放方案 1. MPMoviePlayerController MPMoviePlayerController是一个简单易用的视频播放控件,可以播放本地文件和网络流媒体

[转]iOS微信小视频优化心得

转自:http://www.cnblogs.com/itlover2013/p/5469588.html 小视频是微信6.0版本重大功能之一,在开发过程中遇到不少问题.本文先叙述小视频的产品需求,介绍了几个实现方案,分析每个方案的优缺点,最后总结出最优的解决方案. 小视频播放需求 可以同时播放多个视频 用户操作界面时视频可以继续播放 播放时不能卡住界面,视频滑进界面内后要立即播放 视频在列表内播放是静音播放,点击放大是有声播放 小视频播放方案 1. MPMoviePlayerController

ios设备突破微信小视频6S限制的方法

刷微信朋友圈只发文字和图片怎能意犹未竟,微信小视频是一个很好的补充,音视频到位,流行流行最流行.但小视频时长不能超过6S,没有滤镜等是很大的遗憾.but有人突破限制玩出了花样,用ios设备在朋友圈晒出超时长.带滤镜甚至慢镜头拍摄的小视频.随ytkah一起看看他们是怎么玩的吧 未越狱ios设备在微信朋友圈上传延时.慢动作.滤镜.超时长小视频的方法: 第①步,将iPhone拍摄好的延时.超时长或者慢动作的视频保存到本地电脑,并同时截取一张视频画面保存.(PS:添加滤镜效果可以通过iMovie等App

[iOS]手把手教你实现微信小视频

本文个人原创,转载请注明出处,谢谢. 前段时间项目要求需要在聊天模块中加入类似微信的小视频功能,这边博客主要是为了总结遇到的问题和解决方法,希望能够对有同样需求的朋友有所帮助. 效果预览: 这里先罗列遇到的主要问题: 视频剪裁  微信的小视频只是取了摄像头获取的一部分画面 滚动预览的卡顿问题  AVPlayer播放视频在滚动中会出现很卡的问题 接下来让我们一步步来实现. Part 1 实现视频录制 1.录制类WKMovieRecorder实现 创建一个录制类WKMovieRecorder,负责视

微信小视频复制到手机本地Android APP 分享

因为需要将拍的宝宝的微信小视频上传到亲宝宝软件,每次去手动找文件比较麻烦,所以做了个微信视频复制到手机本地的APP,做工虽然粗糙,但是绝对实用, 下载地址 http://pan.baidu.com/s/1nuSNkCx 三个页面 首页是相册大图预览 第二页是微信视频预览和复制功能,长按单个视频可以单个复制,也可以按全部复制按钮 第三页是复制完成的视频预览

微信小视频微信卡包功能如约现身6.0版本

前面提到微信5.5版内测,今天微信直接跳过5.x版本升级为微信6.0版本,微信小视频和微信卡包功能如约到来,我们来上手体验一下吧. 微信6.0版微信小视频,可在聊天或朋友圈拍摄一段小视频分享给好友 微信聊天界面的⊕添加小视频 在朋友圈中分享微信小视频 微信卡包,把优惠券.会员卡.机票.电影票等发到微信卡包里,方便使用:此外,新版本中还可为微信钱包设置手势密码