Toggle navigation
Toggle navigation
此项目
正在载入...
Sign in
xuning
/
yolo11record
转到一个项目
Toggle navigation
项目
群组
代码片段
帮助
Toggle navigation pinning
Project
Activity
Repository
Pipelines
Graphs
Issues
0
Merge Requests
0
Wiki
Network
Create a new issue
Builds
Commits
Authored by
xuning
2025-09-30 09:16:09 +0800
Browse Files
Options
Browse Files
Download
Email Patches
Plain Diff
Commit
afb9f4e96eab961120e79cb396e5bf6181f3d7b8
afb9f4e9
1 parent
aed36cb3
录音实现
隐藏空白字符变更
内嵌
并排对比
正在显示
1 个修改的文件
包含
217 行增加
和
0 行删除
app/src/main/jni/ndkcamera_recording.cpp
app/src/main/jni/ndkcamera_recording.cpp
0 → 100644
查看文件 @
afb9f4e
// Tencent is pleased to support the open source community by making ncnn available.
//
// Copyright (C) 2025 THL A29 Limited, a Tencent company. All rights reserved.
//
// Licensed under the BSD 3-Clause License (the "License"); you may not use this file except
// in compliance with the License. You may obtain a copy of the License at
//
// https://opensource.org/licenses/BSD-3-Clause
//
// Unless required by applicable law or agreed to in writing, software distributed
// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, either express or implied. See the License for the
// specific language governing permissions and limitations under the License.
#include "ndkcamera.h"
#include <android/log.h>
#include <chrono>
#include <unistd.h>
#define LOG_TAG "NdkCameraRecording"
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__)
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
bool
NdkCameraWindow
::
startRecording
(
const
char
*
filepath
)
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
recording_mutex
);
if
(
recording_active
)
{
LOGE
(
"Recording already active"
);
return
false
;
}
// 初始化录制状态
video_encoder
=
nullptr
;
audio_encoder
=
nullptr
;
media_muxer
=
nullptr
;
recording_active
=
true
;
video_track_index
=
-
1
;
audio_track_index
=
-
1
;
muxer_started
=
false
;
// 创建录制线程
recording_thread
=
new
std
::
thread
(
&
NdkCameraWindow
::
recording_worker
,
this
);
LOGI
(
"Recording started: %s"
,
filepath
);
return
true
;
}
bool
NdkCameraWindow
::
stopRecording
()
{
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
recording_mutex
);
if
(
!
recording_active
)
{
LOGE
(
"Recording not active"
);
return
false
;
}
recording_active
=
false
;
}
// 等待录制线程结束
if
(
recording_thread
&&
recording_thread
->
joinable
())
{
recording_thread
->
join
();
delete
recording_thread
;
recording_thread
=
nullptr
;
}
// 清理资源
if
(
media_muxer
)
{
AMediaMuxer_stop
(
media_muxer
);
AMediaMuxer_delete
(
media_muxer
);
media_muxer
=
nullptr
;
}
if
(
video_encoder
)
{
AMediaCodec_stop
(
video_encoder
);
AMediaCodec_delete
(
video_encoder
);
video_encoder
=
nullptr
;
}
if
(
audio_encoder
)
{
AMediaCodec_stop
(
audio_encoder
);
AMediaCodec_delete
(
audio_encoder
);
audio_encoder
=
nullptr
;
}
LOGI
(
"Recording stopped"
);
return
true
;
}
bool
NdkCameraWindow
::
isRecording
()
const
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
recording_mutex
);
return
recording_active
;
}
void
NdkCameraWindow
::
recording_worker
()
{
// 这里实现录制工作线程
// 由于MediaCodec实现较复杂,这里先提供一个框架
// 实际实现需要处理视频编码、音频编码和混合器
while
(
recording_active
)
{
// 处理视频帧队列
std
::
vector
<
uint8_t
>
frame
;
{
std
::
lock_guard
<
std
::
mutex
>
lock
(
recording_mutex
);
if
(
!
video_frame_queue
.
empty
())
{
frame
=
video_frame_queue
.
front
();
video_frame_queue
.
pop
();
}
}
if
(
!
frame
.
empty
())
{
// 处理视频帧编码
// 这里需要实现MediaCodec编码逻辑
}
// 短暂休眠避免过度占用CPU
usleep
(
1000
);
// 1ms
}
}
bool
NdkCameraWindow
::
setup_video_encoder
(
int
width
,
int
height
,
int
fps
)
{
// 创建视频编码器
const
char
*
mime_type
=
"video/avc"
;
video_encoder
=
AMediaCodec_createEncoderByType
(
mime_type
);
if
(
!
video_encoder
)
{
LOGE
(
"Failed to create video encoder"
);
return
false
;
}
// 配置视频格式
AMediaFormat
*
format
=
AMediaFormat_new
();
AMediaFormat_setString
(
format
,
AMEDIAFORMAT_KEY_MIME
,
mime_type
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_WIDTH
,
width
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_HEIGHT
,
height
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_FRAME_RATE
,
fps
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_I_FRAME_INTERVAL
,
1
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_BIT_RATE
,
2000000
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_COLOR_FORMAT
,
AMEDIACODEC_COLOR_FormatYUV420Flexible
);
// 配置编码器
media_status_t
status
=
AMediaCodec_configure
(
video_encoder
,
format
,
nullptr
,
nullptr
,
AMEDIACODEC_CONFIGURE_FLAG_ENCODE
);
AMediaFormat_delete
(
format
);
if
(
status
!=
AMEDIA_OK
)
{
LOGE
(
"Failed to configure video encoder: %d"
,
status
);
AMediaCodec_delete
(
video_encoder
);
video_encoder
=
nullptr
;
return
false
;
}
// 启动编码器
status
=
AMediaCodec_start
(
video_encoder
);
if
(
status
!=
AMEDIA_OK
)
{
LOGE
(
"Failed to start video encoder: %d"
,
status
);
AMediaCodec_delete
(
video_encoder
);
video_encoder
=
nullptr
;
return
false
;
}
LOGI
(
"Video encoder setup: %dx%d %dfps"
,
width
,
height
,
fps
);
return
true
;
}
bool
NdkCameraWindow
::
setup_audio_encoder
()
{
// 创建音频编码器
const
char
*
mime_type
=
"audio/mp4a-latm"
;
audio_encoder
=
AMediaCodec_createEncoderByType
(
mime_type
);
if
(
!
audio_encoder
)
{
LOGE
(
"Failed to create audio encoder"
);
return
false
;
}
// 配置音频格式
AMediaFormat
*
format
=
AMediaFormat_new
();
AMediaFormat_setString
(
format
,
AMEDIAFORMAT_KEY_MIME
,
mime_type
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_SAMPLE_RATE
,
44100
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_CHANNEL_COUNT
,
1
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_BIT_RATE
,
128000
);
AMediaFormat_setInt32
(
format
,
AMEDIAFORMAT_KEY_AAC_PROFILE
,
2
);
// AAC LC
// 配置编码器
media_status_t
status
=
AMediaCodec_configure
(
audio_encoder
,
format
,
nullptr
,
nullptr
,
AMEDIACODEC_CONFIGURE_FLAG_ENCODE
);
AMediaFormat_delete
(
format
);
if
(
status
!=
AMEDIA_OK
)
{
LOGE
(
"Failed to configure audio encoder: %d"
,
status
);
AMediaCodec_delete
(
audio_encoder
);
audio_encoder
=
nullptr
;
return
false
;
}
// 启动编码器
status
=
AMediaCodec_start
(
audio_encoder
);
if
(
status
!=
AMEDIA_OK
)
{
LOGE
(
"Failed to start audio encoder: %d"
,
status
);
AMediaCodec_delete
(
audio_encoder
);
audio_encoder
=
nullptr
;
return
false
;
}
LOGI
(
"Audio encoder setup"
);
return
true
;
}
void
NdkCameraWindow
::
encode_video_frame
(
const
unsigned
char
*
nv21_data
,
int
width
,
int
height
,
int64_t
timestamp_us
)
{
if
(
!
video_encoder
||
!
recording_active
)
{
return
;
}
// 将视频帧添加到队列供录制线程处理
std
::
vector
<
uint8_t
>
frame_data
(
nv21_data
,
nv21_data
+
width
*
height
*
3
/
2
);
std
::
lock_guard
<
std
::
mutex
>
lock
(
recording_mutex
);
video_frame_queue
.
push
(
std
::
move
(
frame_data
));
}
\ No newline at end of file
...
...
请
注册
或
登录
后发表评论