This commit is contained in:
刘可亮
2024-09-03 11:16:08 +08:00
parent cf270df8d6
commit 803cac77d5
2931 changed files with 614364 additions and 31222 deletions

View File

@@ -0,0 +1,513 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <jun.ma@artinchip.com>
* Desc: aic recorder api
*/
#include <fcntl.h>
#include <malloc.h>
#include <pthread.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include "aic_muxer.h"
#include "aic_recorder.h"
#include "mm_core.h"
#include "mpp_dec_type.h"
#include "mpp_log.h"
#include "mpp_mem.h"
#define AIC_RECORDER_STATE_IDLE 0
#define AIC_RECORDER_STATE_INITIALIZED 1
#define AIC_RECORDER_STATE_RECORDING 2
#define AIC_RECORDER_STATE_STOPPED 3
#define wait_state( \
h_component, \
des_state) \
{ \
MM_STATE_TYPE state; \
while (1) { \
mm_get_state(h_component, &state); \
if (state == des_state) { \
break; \
} else { \
usleep(1000); \
} \
} \
} /* Macro End */
struct aic_recorder {
mm_handle muxer_handle;
mm_handle venc_handle;
mm_handle vin_handle;
mm_handle aenc_handle;
struct aic_recorder_config config;
event_handler event_handle;
void *app_data;
char uri[512];
int state;
};
static s32 component_event_handler(
mm_handle h_component,
void *p_app_data,
MM_EVENT_TYPE event,
u32 data1,
u32 data2,
void *p_event_data)
{
s32 error = MM_ERROR_NONE;
struct aic_recorder *recorder = (struct aic_recorder *)p_app_data;
switch ((s32)event) {
case MM_EVENT_MUXER_NEED_NEXT_FILE:
recorder->event_handle(recorder->app_data,
AIC_RECORDER_EVENT_NEED_NEXT_FILE, 0, 0);
break;
case MM_EVENT_BUFFER_FLAG:
recorder->event_handle(recorder->app_data, AIC_RECORDER_EVENT_COMPLETE, 0, 0);
break;
default:
break;
}
return error;
}
s32 component_giveback_buffer(
mm_handle h_component,
void *p_app_data,
mm_buffer *p_buffer)
{
s32 error = MM_ERROR_NONE;
u64 tmp = (u64)(unsigned long)p_buffer->p_buffer;
struct aic_recorder *recorder = (struct aic_recorder *)p_app_data;
if (h_component == recorder->venc_handle) {
recorder->event_handle(recorder->app_data,
AIC_RECORDER_EVENT_RELEASE_VIDEO_BUFFER,
(u32)tmp, 0);
}
return error;
}
static mm_callback component_event_callbacks = {
.event_handler = component_event_handler,
.giveback_buffer = component_giveback_buffer,
};
struct aic_recorder *aic_recorder_create(void)
{
s32 error;
struct aic_recorder *recorder = mpp_alloc(sizeof(struct aic_recorder));
if (recorder == NULL) {
loge("mpp_alloc aic_recorder error\n");
return NULL;
}
memset(recorder, 0x00, sizeof(struct aic_recorder));
error = mm_init();
if (error != MM_ERROR_NONE) {
loge("mm_init error!!!\n");
mpp_free(recorder);
return NULL;
}
recorder->state = AIC_RECORDER_STATE_IDLE;
return recorder;
}
s32 aic_recorder_destroy(struct aic_recorder *recorder)
{
mm_deinit();
mpp_free(recorder);
return 0;
}
s32 aic_recorder_set_event_callback(struct aic_recorder *recorder,
void *app_data, event_handler event_handle)
{
recorder->event_handle = event_handle;
recorder->app_data = app_data;
return 0;
}
s32 aic_recorder_init(struct aic_recorder *recorder,
struct aic_recorder_config *recorder_config)
{
int ret = 0;
mm_param_port_def port_define;
mm_param_record_file_info rec_file_info;
mm_image_param_qfactor qfactor;
if (!recorder || !recorder_config) {
return -1;
}
recorder->config = *recorder_config;
if (!recorder->config.has_video && !recorder->config.has_audio) {
loge("para error\n");
return -1;
}
// create muxer
if (MM_ERROR_NONE != mm_get_handle(&recorder->muxer_handle,
MM_COMPONENT_MUXER_NAME,
recorder,
&component_event_callbacks)) {
loge("unable to get muxer_handle handle.\n");
return -1;
}
// set muxer para
rec_file_info.duration = recorder->config.file_duration;
rec_file_info.file_num = recorder->config.file_num;
rec_file_info.muxer_type = 0; // only support mp4
if (MM_ERROR_NONE != mm_set_parameter(recorder->muxer_handle,
MM_INDEX_VENDOR_MUXER_RECORD_FILE_INFO,
&rec_file_info)) {
loge("mm_set_parameter error.\n");
ret = -1;
goto _EXIT;
}
// video
if (recorder->config.has_video) {
// create vin
if (MM_ERROR_NONE != mm_get_handle(&recorder->vin_handle,
MM_COMPONENT_VIN_NAME,
recorder,
&component_event_callbacks)) {
loge("unable to get vin_handle handle.\n");
ret = -1;
goto _EXIT;
}
// create venc
if (MM_ERROR_NONE != mm_get_handle(&recorder->venc_handle,
MM_COMPONENT_VENC_NAME,
recorder,
&component_event_callbacks)) {
loge("unable to get venc_handle handle.\n");
ret = -1;
goto _EXIT;
}
// set muxer in_video_port para
port_define.port_index = MUX_PORT_VIDEO_INDEX;
if (MM_ERROR_NONE != mm_get_parameter(recorder->muxer_handle,
MM_INDEX_PARAM_PORT_DEFINITION,
&port_define)) {
loge("mm_get_parameter error.\n");
ret = -1;
goto _EXIT;
}
port_define.format.video.frame_width = recorder->config.video_config.out_width;
port_define.format.video.frame_height = recorder->config.video_config.out_height;
port_define.format.video.framerate = recorder->config.video_config.out_frame_rate;
port_define.format.video.bitrate = recorder->config.video_config.out_bit_rate;
if (recorder->config.video_config.codec_type != MPP_CODEC_VIDEO_DECODER_MJPEG) {
loge("only support MPP_CODEC_VIDEO_DECODER_MJPEG.\n");
ret = -1;
goto _EXIT;
}
port_define.format.video.compression_format = MM_VIDEO_CODING_MJPEG;
if (MM_ERROR_NONE != mm_set_parameter(recorder->muxer_handle,
MM_INDEX_PARAM_PORT_DEFINITION,
&port_define)) {
loge("mm_set_parameter error.\n");
ret = -1;
goto _EXIT;
}
// set venc in_port para
if (MM_ERROR_NONE != mm_get_parameter(recorder->venc_handle,
MM_INDEX_PARAM_PORT_DEFINITION,
&port_define)) {
loge("mm_set_parameter error.\n");
ret = -1;
goto _EXIT;
}
port_define.format.video.frame_width = recorder->config.video_config.out_width;
port_define.format.video.frame_height = recorder->config.video_config.out_height;
port_define.format.video.framerate = recorder->config.video_config.out_frame_rate;
port_define.format.video.bitrate = recorder->config.video_config.out_bit_rate;
port_define.format.video.compression_format = MM_VIDEO_CODING_MJPEG;
if (MM_ERROR_NONE != mm_set_parameter(recorder->venc_handle,
MM_INDEX_PARAM_PORT_DEFINITION,
&port_define)) {
loge("mm_set_parameter error.\n");
ret = -1;
goto _EXIT;
}
qfactor.q_factor = recorder->config.qfactor;
if (MM_ERROR_NONE != mm_set_parameter(recorder->venc_handle,
MM_INDEX_PARAM_QFACTOR,
&qfactor)) {
loge("mm_set_parameter error.\n");
ret = -1;
goto _EXIT;
}
port_define.format.video.frame_width = recorder->config.video_config.out_width;
port_define.format.video.frame_height = recorder->config.video_config.out_height;
port_define.format.video.framerate = recorder->config.video_config.out_frame_rate;
port_define.format.video.color_format = MM_COLOR_FORMAT_YUV420P;
if (MM_ERROR_NONE != mm_set_parameter(recorder->vin_handle,
MM_INDEX_PARAM_PORT_DEFINITION,
&port_define)) {
loge("mm_set_parameter error.\n");
ret = -1;
goto _EXIT;
}
// setup bind VENC_PORT_OUT_INDEX--->MUX_PORT_VIDEO_INDEX
if (MM_ERROR_NONE != mm_set_bind(recorder->venc_handle,
VENC_PORT_OUT_INDEX,
recorder->muxer_handle,
MUX_PORT_VIDEO_INDEX)) {
loge("mm_set_bind venc and muxer error.\n");
ret = -1;
goto _EXIT;
}
// setup bind VIN_PORT_OUT_INDEX--->VENC_PORT_VIDEO_INDEX
if (MM_ERROR_NONE != mm_set_bind(recorder->vin_handle,
VIN_PORT_OUT_INDEX,
recorder->venc_handle,
VENC_PORT_IN_INDEX)) {
loge("mm_set_bind vin and venc error.\n");
ret = -1;
goto _EXIT;
}
}
// audio
if (recorder->config.has_audio) {
}
if (recorder->muxer_handle) {
mm_send_command(recorder->muxer_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
}
if (recorder->venc_handle) {
mm_send_command(recorder->venc_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
}
if (recorder->vin_handle) {
mm_send_command(recorder->vin_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
}
if (recorder->aenc_handle) {
mm_send_command(recorder->aenc_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
}
recorder->state = AIC_RECORDER_STATE_INITIALIZED;
return ret;
_EXIT:
if (recorder->muxer_handle) {
mm_free_handle(recorder->muxer_handle);
recorder->muxer_handle = NULL;
}
if (recorder->venc_handle) {
mm_free_handle(recorder->venc_handle);
recorder->venc_handle = NULL;
}
if (recorder->vin_handle) {
mm_free_handle(recorder->vin_handle);
recorder->vin_handle = NULL;
}
if (recorder->aenc_handle) {
mm_free_handle(recorder->aenc_handle);
recorder->aenc_handle = NULL;
}
return ret;
}
s32 aic_recorder_start(struct aic_recorder *recorder)
{
if (recorder->config.has_video && recorder->vin_handle) {
mm_send_command(recorder->vin_handle, MM_COMMAND_STATE_SET, MM_STATE_EXECUTING, NULL);
}
if (recorder->config.has_video && recorder->venc_handle) {
mm_send_command(recorder->venc_handle, MM_COMMAND_STATE_SET, MM_STATE_EXECUTING, NULL);
}
if (recorder->config.has_audio && recorder->aenc_handle) {
mm_send_command(recorder->aenc_handle, MM_COMMAND_STATE_SET, MM_STATE_EXECUTING, NULL);
}
if (recorder->muxer_handle) {
mm_send_command(recorder->muxer_handle, MM_COMMAND_STATE_SET, MM_STATE_EXECUTING, NULL);
}
recorder->state = AIC_RECORDER_STATE_RECORDING;
return 0;
}
s32 aic_recorder_stop(struct aic_recorder *recorder)
{
if (recorder->state == AIC_RECORDER_STATE_IDLE) {
printf("%s:%d\n", __FUNCTION__, __LINE__);
goto _FREE_HANDLE_;
}
if (recorder->muxer_handle) {
mm_send_command(recorder->muxer_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
wait_state(recorder->muxer_handle, MM_STATE_IDLE);
mm_send_command(recorder->muxer_handle, MM_COMMAND_STATE_SET, MM_STATE_LOADED, NULL);
wait_state(recorder->muxer_handle, MM_STATE_LOADED);
}
if (recorder->config.has_video) {
if (recorder->venc_handle) {
mm_send_command(recorder->venc_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
wait_state(recorder->venc_handle, MM_STATE_IDLE);
mm_send_command(recorder->venc_handle, MM_COMMAND_STATE_SET, MM_STATE_LOADED, NULL);
wait_state(recorder->venc_handle, MM_STATE_LOADED);
}
if (recorder->vin_handle) {
mm_send_command(recorder->vin_handle, MM_COMMAND_STATE_SET, MM_STATE_IDLE, NULL);
wait_state(recorder->vin_handle, MM_STATE_IDLE);
mm_send_command(recorder->vin_handle, MM_COMMAND_STATE_SET, MM_STATE_LOADED, NULL);
wait_state(recorder->vin_handle, MM_STATE_LOADED);
}
}
if (recorder->config.has_video) {
if (recorder->muxer_handle && recorder->venc_handle) {
mm_set_bind(recorder->venc_handle, VENC_PORT_OUT_INDEX, NULL, 0);
mm_set_bind(NULL, 0, recorder->muxer_handle, MUX_PORT_VIDEO_INDEX);
}
if (recorder->venc_handle && recorder->vin_handle) {
mm_set_bind(recorder->vin_handle, VENC_PORT_OUT_INDEX, NULL, 0);
mm_set_bind(NULL, 0, recorder->venc_handle, MUX_PORT_VIDEO_INDEX);
}
}
_FREE_HANDLE_:
if (recorder->muxer_handle) {
mm_free_handle(recorder->muxer_handle);
recorder->muxer_handle = NULL;
}
if (recorder->venc_handle) {
mm_free_handle(recorder->venc_handle);
recorder->venc_handle = NULL;
}
if (recorder->vin_handle) {
mm_free_handle(recorder->vin_handle);
recorder->vin_handle = NULL;
}
if (recorder->aenc_handle) {
mm_free_handle(recorder->aenc_handle);
recorder->aenc_handle = NULL;
}
return 0;
}
s32 aic_recorder_set_output_file_path(struct aic_recorder *recorder, char *uri)
{
int bytes;
mm_param_content_uri *uri_param;
if (!recorder || !uri) {
loge("param error\n");
return -1;
}
memset(recorder->uri, 0x00, sizeof(recorder->uri));
strncpy(recorder->uri, uri, sizeof(recorder->uri) - 1);
bytes = strlen(recorder->uri);
uri_param = (mm_param_content_uri *)mpp_alloc(sizeof(mm_param_content_uri) + bytes);
uri_param->size = sizeof(mm_param_content_uri) + bytes;
strcpy((char *)uri_param->content_uri, recorder->uri);
mm_set_parameter(recorder->muxer_handle, MM_INDEX_PARAM_CONTENT_URI, uri_param);
mpp_free(uri_param);
return 0;
}
s32 aic_recorder_set_input_file_path(struct aic_recorder *recorder, char *video_uri, char *audio_uri)
{
int bytes;
mm_param_content_uri *uri_param;
if (!recorder || !video_uri) {
loge("param error\n");
return -1;
}
memset(recorder->uri, 0x00, sizeof(recorder->uri));
strncpy(recorder->uri, video_uri, sizeof(recorder->uri) - 1);
bytes = strlen(recorder->uri);
uri_param = (mm_param_content_uri *)mpp_alloc(sizeof(mm_param_content_uri) + bytes);
uri_param->size = sizeof(mm_param_content_uri) + bytes;
strcpy((char *)uri_param->content_uri, recorder->uri);
mm_set_parameter(recorder->vin_handle, MM_INDEX_PARAM_CONTENT_URI, uri_param);
mpp_free(uri_param);
return 0;
}
s32 aic_recorder_set_vin_type(struct aic_recorder *recorder, enum aic_recorder_vin_type type)
{
if (!recorder || !recorder->vin_handle) {
loge("recorder or vin_handle is null\n");
return -1;
}
mm_param_u32 param;
if (type == AIC_RECORDER_VIN_DVP) {
param.u32 = MM_VIDEO_IN_SOURCE_DVP;
} else if (type == AIC_RECORDER_VIN_USB) {
param.u32 = MM_VIDEO_IN_SOURCE_USB;
} else {
param.u32 = MM_VIDEO_IN_SOURCE_FILE;
}
return mm_set_parameter(recorder->vin_handle, MM_INDEX_PARAM_VIDEO_INPUT_SOURCE, (void *)&param);
}
s32 aic_recorder_set_max_duration(struct aic_recorder *recorder)
{
return 0;
}
s32 aic_recorder_snapshot(struct aic_recorder *recorder, struct aic_record_snapshot_info *snapshot_info)
{
if (!recorder || !recorder->venc_handle) {
loge("recorder or venc_handle is null\n");
return -1;
}
mm_param_video_capture capture;
capture.p_file_path = (s8 *)snapshot_info->file_path;
if (MM_ERROR_NONE != mm_set_config(recorder->venc_handle,
MM_INDEX_VENDOR_VIDEO_ENC_CAPTURE, &capture)) {
loge("no video!!!!\n");
return -1;
}
return 0;
}
s32 aic_recorder_print_debug_info(struct aic_recorder *recorder)
{
if (!recorder) {
loge("recorder is null\n");
return -1;
}
if (recorder->vin_handle) {
mm_set_parameter(recorder->vin_handle, MM_INDEX_PARAM_PRINT_DEBUG_INFO, NULL);
}
if (recorder->venc_handle) {
mm_set_parameter(recorder->venc_handle, MM_INDEX_PARAM_PRINT_DEBUG_INFO, NULL);
}
if (recorder->muxer_handle) {
mm_set_parameter(recorder->muxer_handle, MM_INDEX_PARAM_PRINT_DEBUG_INFO, NULL);
}
return 0;
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <jun.ma@artinchip.com>
* Desc: aic recorder api
*/
#ifndef __AIC_RECORDER_H__
#define __AIC_RECORDER_H__
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
#include "mpp_dec_type.h"
#include "aic_middle_media_common.h"
struct aic_recorder;
struct video_encoding_config {
enum mpp_codec_type codec_type;
s32 out_width;
s32 out_height;
s32 out_bit_rate;
s32 out_frame_rate;
s32 out_qfactor;
// now must be out_width = in_width and out_height= in_height
// case mjpeg encoder has no scale function
s32 in_width;
s32 in_height;
s32 in_pix_fomat;
};
struct audio_encoding_config {
enum aic_audio_codec_type codec_type;
int out_bitrate;
int out_samplerate;
int out_channels;
int out_bits_per_sample;
int in_samplerate;
int in_channels;
int in_bits_per_sample;
};
struct aic_recorder_config {
int file_duration; // unit:second one file duration
int file_num; // 0-loop, >0 record file_num and then stop recording.
int file_muxer_type; // only support mp4
int qfactor;
s8 has_video;
s8 has_audio;
struct audio_encoding_config audio_config;
struct video_encoding_config video_config;
};
struct aic_record_snapshot_info {
s8 *file_path;
};
enum aic_recorder_event {
AIC_RECORDER_EVENT_NEED_NEXT_FILE = 0,
AIC_RECORDER_EVENT_COMPLETE, // when file_num > 0,record file_num then send this event
AIC_RECORDER_EVENT_NO_SPACE,
AIC_RECORDER_EVENT_RELEASE_VIDEO_BUFFER // notify app input_frame has used.
};
enum aic_recorder_vin_type {
AIC_RECORDER_VIN_FILE = 0,
AIC_RECORDER_VIN_DVP,
AIC_RECORDER_VIN_USB,
};
typedef s32 (*event_handler)(void *app_data, s32 event, s32 data1, s32 data2);
struct aic_recorder *aic_recorder_create(void);
s32 aic_recorder_destroy(struct aic_recorder *recorder);
s32 aic_recorder_set_event_callback(struct aic_recorder *recorder, void *app_data, event_handler event_handle);
s32 aic_recorder_set_input_file_path(struct aic_recorder *recorder, char *video_uri, char *audio_uri);
s32 aic_recorder_set_output_file_path(struct aic_recorder *recorder, char *uri);
s32 aic_recorder_init(struct aic_recorder *recorder, struct aic_recorder_config *recorder_config);
s32 aic_recorder_start(struct aic_recorder *recorder);
s32 aic_recorder_stop(struct aic_recorder *recorder);
s32 aic_recorder_snapshot(struct aic_recorder *recorder, struct aic_record_snapshot_info *snapshot_info);
s32 aic_recorder_set_vin_type(struct aic_recorder *recorder, enum aic_recorder_vin_type type);
s32 aic_recorder_print_debug_info(struct aic_recorder *recorder);
#ifdef __cplusplus
}
#endif /* End of #ifdef __cplusplus */
#endif

View File

@@ -0,0 +1,574 @@
/*
* Copyright (C) 2020-2024 ArtInChip Technology Co. Ltd
*
* SPDX-License-Identifier: Apache-2.0
*
* Author: <jun.ma@artinchip.com>
* Desc: recorder demo
*/
#include <fcntl.h>
#include <pthread.h>
#include <rthw.h>
#include <rtthread.h>
#include <shell.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <getopt.h>
#include <time.h>
#define LOG_DEBUG
#include "aic_recorder.h"
#include "cJSON.h"
#include "mpp_list.h"
#include "mpp_log.h"
#include "mpp_mem.h"
#ifdef LPKG_USING_CPU_USAGE
#include "cpu_usage.h"
#endif
#define RECORDER_DEMO_DEFAULT_RECORD_TIME 0x7FFFFFFF
/*You can only choose thread trace or cpu trace*/
#define RECORD_THREAD_TRACE_INFO
//#define RECORD_CPU_TRACE_INFO
static void print_help(const char* prog)
{
printf("name: %s\n", prog);
printf("Compile time: %s\n", __TIME__);
printf("Usage: recoder_demo [options]:\n"
"\t-i video input source\n"
"\t-t recoder time(s)\n"
"\t-c recoder config file\n"
"\t-h help\n\n"
"Example1: recoder_demo -i dvp -t 60 -c /sdcard/recorder.config\n"
"Example2: recoder_demo -i file -t 60 -c /sdcard/recorder.config\n");
}
static void print_cmd_help(const char* prog)
{
printf("name: %s\n", prog);
printf("Compile time: %s\n", __TIME__);
printf("Usage: recoder_demo_cmd [options]:\n"
"\tstop stop recorder\n"
"\tsnap snap one frame\n"
"\tdebug get debug info\n"
"\t help\n\n");
}
char *read_file(const char *filename)
{
FILE *file = NULL;
long length = 0;
char *content = NULL;
size_t read_chars = 0;
/* open in read binary mode */
file = fopen(filename, "rb");
if (file == NULL) {
goto cleanup;
}
/* get the length */
if (fseek(file, 0, SEEK_END) != 0) {
goto cleanup;
}
length = ftell(file);
if (length < 0) {
goto cleanup;
}
if (fseek(file, 0, SEEK_SET) != 0) {
goto cleanup;
}
/* allocate content buffer */
content = (char *)malloc((size_t)length + sizeof(""));
if (content == NULL) {
goto cleanup;
}
/* read the file into memory */
read_chars = fread(content, sizeof(char), (size_t)length, file);
if ((long)read_chars != length) {
free(content);
content = NULL;
goto cleanup;
}
content[read_chars] = '\0';
cleanup:
if (file != NULL) {
fclose(file);
}
return content;
}
static cJSON *parse_file(const char *filename)
{
cJSON *parsed = NULL;
char *content = read_file(filename);
parsed = cJSON_Parse(content);
if (content != NULL) {
free(content);
}
return parsed;
}
struct recorder_context {
struct aic_recorder *recorder;
enum aic_recorder_vin_type vin_source_type;
char config_file_path[256];
char video_in_file_path[256];
char audio_in_file_path[256];
char output_file_path[256];
char capture_file_path[256];
struct aic_recorder_config config;
unsigned int record_time;
};
static int g_recorder_flag = 0;
static struct recorder_context *g_recorder_cxt = NULL;
static s32 event_handle(void *app_data, s32 event, s32 data1, s32 data2)
{
int ret = 0;
struct recorder_context *recorder_cxt = (struct recorder_context *)app_data;
char file_path[512] = {0};
time_t timep;
struct tm *p = NULL;
switch (event) {
case AIC_RECORDER_EVENT_NEED_NEXT_FILE:
// set recorder file name
time(&timep);
p = localtime(&timep);
snprintf(file_path, sizeof(file_path), "%s%04d%02d%02d_%02d%02d%02d.mp4",
recorder_cxt->output_file_path,
1900 + p->tm_year, 1 + p->tm_mon, p->tm_mday,
p->tm_hour, 1 + p->tm_min, p->tm_sec);
aic_recorder_set_output_file_path(recorder_cxt->recorder, file_path);
printf("set recorder file:%s\n", file_path);
break;
case AIC_RECORDER_EVENT_COMPLETE:
g_recorder_flag = 1;
break;
case AIC_RECORDER_EVENT_NO_SPACE:
break;
default:
break;
}
return ret;
}
int parse_config_file(char *config_file, struct recorder_context *recorder_cxt)
{
int ret = 0;
cJSON *cjson = NULL;
cJSON *root = NULL;
if (!config_file || !recorder_cxt) {
ret = -1;
goto _EXIT;
}
root = parse_file(config_file);
if (!root) {
loge("parse_file error %s!!!", config_file);
ret = -1;
goto _EXIT;
}
cjson = cJSON_GetObjectItem(root, "video_in_file");
if (!cjson) {
loge("no video_in_file error");
ret = -1;
goto _EXIT;
}
strcpy(recorder_cxt->video_in_file_path, cjson->valuestring);
cjson = cJSON_GetObjectItem(root, "audio_in_file");
if (!cjson) {
strcpy(recorder_cxt->audio_in_file_path, cjson->valuestring);
}
cjson = cJSON_GetObjectItem(root, "output_file");
if (!cjson) {
loge("no output_file error");
ret = -1;
goto _EXIT;
}
strcpy(recorder_cxt->output_file_path, cjson->valuestring);
cjson = cJSON_GetObjectItem(root, "file_duration");
if (cjson) {
recorder_cxt->config.file_duration = cjson->valueint * 1000;
}
cjson = cJSON_GetObjectItem(root, "file_num");
if (cjson) {
recorder_cxt->config.file_num = cjson->valueint;
}
cjson = cJSON_GetObjectItem(root, "qfactor");
if (cjson) {
recorder_cxt->config.qfactor = cjson->valueint;
}
cjson = cJSON_GetObjectItem(root, "video");
if (cjson) {
int enable = cJSON_GetObjectItem(cjson, "enable")->valueint;
if (enable == 1) {
recorder_cxt->config.has_video = 1;
}
recorder_cxt->config.video_config.codec_type =
cJSON_GetObjectItem(cjson, "codec_type")->valueint;
printf("codec_type:0x%x\n", recorder_cxt->config.video_config.codec_type);
if (recorder_cxt->config.video_config.codec_type != MPP_CODEC_VIDEO_DECODER_MJPEG) {
ret = -1;
loge("only support MPP_CODEC_VIDEO_DECODER_MJPEG");
g_recorder_flag = 1;
goto _EXIT;
}
recorder_cxt->config.video_config.out_width =
cJSON_GetObjectItem(cjson, "out_width")->valueint;
recorder_cxt->config.video_config.out_height =
cJSON_GetObjectItem(cjson, "out_height")->valueint;
recorder_cxt->config.video_config.out_frame_rate =
cJSON_GetObjectItem(cjson, "out_framerate")->valueint;
recorder_cxt->config.video_config.out_bit_rate =
cJSON_GetObjectItem(cjson, "out_bitrate")->valueint;
recorder_cxt->config.video_config.in_width =
cJSON_GetObjectItem(cjson, "in_width")->valueint;
recorder_cxt->config.video_config.in_height =
cJSON_GetObjectItem(cjson, "in_height")->valueint;
recorder_cxt->config.video_config.in_pix_fomat =
cJSON_GetObjectItem(cjson, "in_pix_format")->valueint;
}
cjson = cJSON_GetObjectItem(root, "audio");
if (cjson) {
int enable = cJSON_GetObjectItem(cjson, "enable")->valueint;
if (enable == 1) {
recorder_cxt->config.has_audio = 1;
}
recorder_cxt->config.audio_config.codec_type =
cJSON_GetObjectItem(cjson, "codec_type")->valueint;
recorder_cxt->config.audio_config.out_bitrate =
cJSON_GetObjectItem(cjson, "out_bitrate")->valueint;
recorder_cxt->config.audio_config.out_samplerate =
cJSON_GetObjectItem(cjson, "out_samplerate")->valueint;
recorder_cxt->config.audio_config.out_channels =
cJSON_GetObjectItem(cjson, "out_channels")->valueint;
recorder_cxt->config.audio_config.out_bits_per_sample =
cJSON_GetObjectItem(cjson, "out_bits_per_sample")->valueint;
recorder_cxt->config.audio_config.in_samplerate =
cJSON_GetObjectItem(cjson, "in_samplerate")->valueint;
recorder_cxt->config.audio_config.in_channels =
cJSON_GetObjectItem(cjson, "in_channels")->valueint;
recorder_cxt->config.audio_config.in_bits_per_sample =
cJSON_GetObjectItem(cjson, "in_bits_per_sample")->valueint;
}
_EXIT:
if (root) {
cJSON_Delete(root);
}
return ret;
}
static int parse_options(struct recorder_context *recoder_ctx, int cnt, char **options)
{
int argc = cnt;
char **argv = options;
struct recorder_context *ctx = recoder_ctx;
int opt;
if (!ctx || argc == 0 || !argv) {
loge("para error !!!");
return -1;
}
optind = 0;
while (1) {
opt = getopt(argc, argv, "i:c:t:h");
if (opt == -1) {
break;
}
switch (opt) {
case 'i':
if (strcmp(optarg, "dvp") == 0) {
ctx->vin_source_type = AIC_RECORDER_VIN_DVP;
} else {
ctx->vin_source_type = AIC_RECORDER_VIN_FILE;
}
break;
case 'c':
strcpy(ctx->config_file_path, optarg);
break;
case 't':
ctx->record_time = atoi(optarg);
break;
case 'h':
default:
print_help(argv[0]);
return -1;
}
}
return 0;
}
static void show_cpu_usage()
{
#if defined(LPKG_USING_CPU_USAGE) && defined(RECORD_CPU_TRACE_INFO)
static int index = 0;
char data_str[64];
float value = 0.0;
if (index++ % 30 == 0) {
value = cpu_load_average();
#ifdef AIC_PRINT_FLOAT_CUSTOM
int cpu_i;
int cpu_frac;
cpu_i = (int)value;
cpu_frac = (value - cpu_i) * 100;
snprintf(data_str, sizeof(data_str), "%d.%02d\n", cpu_i, cpu_frac);
#else
snprintf(data_str, sizeof(data_str), "%.2f\n", value);
#endif
printf("cpu_loading:%s\n",data_str);
}
#endif
}
#ifdef RECORD_THREAD_TRACE_INFO
struct thread_trace_info {
uint32_t enter_run_tick;
uint32_t total_run_tick;
char thread_name[8];
};
static uint32_t sys_tick = 0;
static struct thread_trace_info thread_trace_infos[6];
void print_thread_status()
{
printf("\n");
rt_kprintf("thread\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\t%10s\n"
,thread_trace_infos[0].thread_name
,thread_trace_infos[1].thread_name
,thread_trace_infos[2].thread_name
,thread_trace_infos[3].thread_name
,thread_trace_infos[4].thread_name
,thread_trace_infos[5].thread_name
,"thread0-5", "Total");
rt_kprintf("tick\t%10u\t%10u\t%10u\t%10u\t%10u\t%10u\t%10u\t%10u\n"
,thread_trace_infos[0].total_run_tick
,thread_trace_infos[1].total_run_tick
,thread_trace_infos[2].total_run_tick
,thread_trace_infos[3].total_run_tick
,thread_trace_infos[4].total_run_tick
,thread_trace_infos[5].total_run_tick
,thread_trace_infos[5].total_run_tick+
thread_trace_infos[4].total_run_tick+
thread_trace_infos[3].total_run_tick+
thread_trace_infos[2].total_run_tick+
thread_trace_infos[1].total_run_tick+
thread_trace_infos[0].total_run_tick
,rt_tick_get() - sys_tick);
}
// count the cpu usage time of each thread
static void hook_of_scheduler(struct rt_thread *from,struct rt_thread *to) {
static int show = 0;
int i = 0;
for(i=0;i<6;i++) {
if (!strcmp(thread_trace_infos[i].thread_name,from->name)) {
uint32_t run_tick;
run_tick = rt_tick_get() - thread_trace_infos[i].enter_run_tick;
thread_trace_infos[i].total_run_tick += run_tick;
break;
}
}
for(i=0;i<6;i++) {
if (!strcmp(thread_trace_infos[i].thread_name,to->name)) {
thread_trace_infos[i].enter_run_tick = rt_tick_get();
break;
}
}
show++;
if (show > 10*1000) {
print_thread_status();
for(i=0;i<6;i++) {
thread_trace_infos[i].total_run_tick = 0;
}
show = 0;
sys_tick = rt_tick_get();
}
}
#endif
static void *test_recorder_thread(void *arg)
{
struct recorder_context *recorder_cxt = (struct recorder_context *)arg;
struct timespec start_time = { 0 }, cur_time = { 0 };
clock_gettime(CLOCK_REALTIME, &start_time);
while (!g_recorder_flag) {
clock_gettime(CLOCK_REALTIME, &cur_time);
if (recorder_cxt->record_time <= (cur_time.tv_sec - start_time.tv_sec)) {
g_recorder_flag = 1;
break;
}
show_cpu_usage();
usleep(100 * 1000);
}
if (recorder_cxt && recorder_cxt->recorder) {
aic_recorder_stop(recorder_cxt->recorder);
aic_recorder_destroy(recorder_cxt->recorder);
recorder_cxt->recorder = NULL;
}
if (recorder_cxt) {
free(recorder_cxt);
recorder_cxt = NULL;
}
printf("test_recorder_thread exit\n");
return NULL;
}
int recorder_demo_test(int argc, char *argv[])
{
int ret = 0;
pthread_attr_t attr;
pthread_t thread_id;
struct recorder_context *recorder_cxt = NULL;
g_recorder_flag = 0;
recorder_cxt = malloc(sizeof(struct recorder_context));
if (!recorder_cxt) {
loge("malloc error");
return -1;
}
memset(recorder_cxt, 0x00, sizeof(struct recorder_context));
recorder_cxt->record_time = RECORDER_DEMO_DEFAULT_RECORD_TIME;
if (parse_options(recorder_cxt, argc, argv)) {
goto _EXIT;
}
g_recorder_cxt = recorder_cxt;
if (parse_config_file(recorder_cxt->config_file_path, recorder_cxt)) {
loge("parse_config_file %s error", recorder_cxt->config_file_path);
goto _EXIT;
}
#ifdef RECORD_THREAD_TRACE_INFO
memset(&thread_trace_infos, 0x00, sizeof(struct thread_trace_info));
for (int i = 0; i < 6; i++) {
snprintf(thread_trace_infos[i].thread_name, sizeof(thread_trace_infos[i].thread_name),
"%s%02d", "pth", i);
printf("%s\n", thread_trace_infos[i].thread_name);
}
rt_scheduler_sethook(hook_of_scheduler);
#endif
recorder_cxt->recorder = aic_recorder_create();
if (!recorder_cxt->recorder) {
loge("aic_recorder_create error");
goto _EXIT;
}
if (aic_recorder_set_event_callback(recorder_cxt->recorder,
recorder_cxt, event_handle)) {
loge("aic_recorder_set_event_callback error");
goto _EXIT;
}
if (aic_recorder_init(recorder_cxt->recorder, &recorder_cxt->config)) {
loge("aic_recorder_init error");
goto _EXIT;
}
aic_recorder_set_vin_type(recorder_cxt->recorder, recorder_cxt->vin_source_type);
aic_recorder_set_input_file_path(recorder_cxt->recorder, recorder_cxt->video_in_file_path, NULL);
if (aic_recorder_start(recorder_cxt->recorder)) {
loge("aic_recorder_start error");
goto _EXIT;
}
pthread_attr_init(&attr);
attr.stacksize = 2 * 1024;
attr.schedparam.sched_priority = 30;
ret = pthread_create(&thread_id, &attr, test_recorder_thread, recorder_cxt);
if (ret) {
loge("create test_recorder_thread failed\n");
}
return ret;
_EXIT:
if (recorder_cxt && recorder_cxt->recorder) {
aic_recorder_stop(recorder_cxt->recorder);
aic_recorder_destroy(recorder_cxt->recorder);
recorder_cxt->recorder = NULL;
}
if (recorder_cxt) {
free(recorder_cxt);
recorder_cxt = NULL;
}
return ret;
}
MSH_CMD_EXPORT_ALIAS(recorder_demo_test, recorder_demo, recorder demo);
int recorder_demo_cmd(int argc, char *argv[])
{
int ret = 0;
static int capture_count = 0;
struct recorder_context *recorder_cxt = g_recorder_cxt;
if (argc < 1) {
print_cmd_help(argv[0]);
return -1;
}
if (strcmp(argv[1], "stop") == 0) {
g_recorder_flag = 1;
} else if (strcmp(argv[1], "snap") == 0) {
struct aic_record_snapshot_info snap_info;
snprintf(recorder_cxt->capture_file_path, sizeof(recorder_cxt->capture_file_path),
"/sdcard/capture-%d.jpg", capture_count++);
snap_info.file_path = (s8 *)recorder_cxt->capture_file_path;
aic_recorder_snapshot(recorder_cxt->recorder, &snap_info);
} else if (strcmp(argv[1], "debug") == 0) {
aic_recorder_print_debug_info(recorder_cxt->recorder);
} else {
print_cmd_help(argv[0]);
}
return ret;
}
MSH_CMD_EXPORT_ALIAS(recorder_demo_cmd, recorder_demo_cmd, recorder demo cmd);

View File

@@ -0,0 +1,33 @@
{
"video_in_file":"/sdcard/test.yuv",
"audio_in_file":"/sdcard/test.pcm",
"output_file":"/sdcard/",
"file_duration":40,
"file_num":0,
"file_muxer_type":0,
"qfactor":80,
"video":
{
"enable":1,
"codec_type":4097,
"out_width":320,
"out_height":240,
"out_framerate":25,
"out_bitrate":1300,
"in_width":320,
"in_height":240,
"in_pix_format":32
},
"audio":
{
"enable":0,
"codec_type":1,
"out_bitrate":128000,
"out_samplerate":48000,
"out_channels":2,
"out_bits_per_sample":16,
"in_samplerate":48000,
"in_channels":2,
"in_bits_per_sample":16
}
}