This commit is contained in:
huxi
2025-12-03 11:12:34 +08:00
parent c23ae4f24c
commit bc195654bf
8163 changed files with 3799544 additions and 92 deletions
File diff suppressed because it is too large Load Diff
+350
View File
@@ -0,0 +1,350 @@
/*
* avilib.h
*
* Copyright (C) Thomas streich - June 2001
* multiple audio track support Copyright (C) 2002 Thomas streich
*
* Original code:
* Copyright (C) 1999 Rainer Johanni <Rainer@Johanni.de>
*
* This file is part of transcode, a linux video stream processing tool
*
* transcode is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* transcode is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with GNU Make; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#ifndef AVILIB_H
#define AVILIB_H
#include "system/includes.h"
#include <limits.h>
typedef long off_t;
#define AVI_MAX_TRACKS 8
typedef struct {
off_t key;
off_t pos;
off_t len;
} video_index_entry;
typedef struct {
off_t pos;
off_t len;
off_t tot;
} audio_index_entry;
typedef struct track_s {
long a_fmt; /* Audio format, see #defines below */
long a_chans; /* Audio channels, 0 for no audio */
long a_rate; /* Rate in Hz */
long a_bits; /* bits per audio sample */
long mp3rate; /* mp3 bitrate kbs*/
long audio_strn; /* Audio stream number */
off_t audio_bytes; /* Total number of bytes of audio data */
long audio_chunks; /* Chunks of audio data in the file */
char audio_tag[4]; /* Tag of audio data */
long audio_posc; /* Audio position: chunk */
long audio_posb; /* Audio position: byte within chunk */
off_t a_codech_off; /* absolut offset of audio codec information */
off_t a_codecf_off; /* absolut offset of audio codec information */
audio_index_entry *audio_index;
} track_t;
typedef struct {
uint32_t bi_size;
uint32_t bi_width;
uint32_t bi_height;
uint16_t bi_planes;
uint16_t bi_bit_count;
uint32_t bi_compression;
uint32_t bi_size_image;
uint32_t bi_x_pels_per_meter;
uint32_t bi_y_pels_per_meter;
uint32_t bi_clr_used;
uint32_t bi_clr_important;
} BITMAPINFOHEADER_avilib;
typedef struct {
uint16_t w_format_tag;
uint16_t n_channels;
uint32_t n_samples_per_sec;
uint32_t n_avg_bytes_per_sec;
uint16_t n_block_align;
uint16_t w_bits_per_sample;
uint16_t cb_size;
} WAVEFORMATEX_avilib;
typedef struct {
uint32_t fcc_type;
uint32_t fcc_handler;
uint32_t dw_flags;
uint32_t dw_caps;
uint16_t w_priority;
uint16_t w_language;
uint32_t dw_scale;
uint32_t dw_rate;
uint32_t dw_start;
uint32_t dw_length;
uint32_t dw_initial_frames;
uint32_t dw_suggested_buffer_size;
uint32_t dw_quality;
uint32_t dw_sample_size;
uint32_t dw_left;
uint32_t dw_top;
uint32_t dw_right;
uint32_t dw_bottom;
uint32_t dw_edit_count;
uint32_t dw_format_change_count;
char sz_name[64];
} AVISTREAMINFO;
typedef struct {
void *fdes; /* File descriptor of AVI file */
long mode; /* 0 for reading, 1 for writing */
long width; /* Width of a video frame */
long height; /* Height of a video frame */
double fps; /* Frames per second */
char compressor[8]; /* Type of compressor, 4 bytes + padding for 0 byte */
char compressor2[8]; /* Type of compressor, 4 bytes + padding for 0 byte */
long video_strn; /* Video stream number */
long video_frames; /* Number of video frames */
char video_tag[4]; /* Tag of video data */
long video_pos; /* Number of next frame to be read
(if index present) */
unsigned long max_len; /* maximum video chunk present */
track_t track[AVI_MAX_TRACKS]; // up to AVI_MAX_TRACKS audio tracks supported
off_t pos; /* position in file */
long n_idx; /* number of index entries actually filled */
long max_idx; /* number of index entries actually allocated */
off_t v_codech_off; /* absolut offset of video codec (strh) info */
off_t v_codecf_off; /* absolut offset of video codec (strf) info */
unsigned char (*idx)[16]; /* index entries (AVI idx1 tag) */
video_index_entry *video_index;
off_t last_pos; /* Position of last frame written */
unsigned long last_len; /* Length of last frame written */
int must_use_index; /* Flag if frames are duplicated */
off_t movi_start;
int anum; // total number of audio tracks
int aptr; // current audio working track
long SuggestedBufferSize; //SuggestedBufferSize
BITMAPINFOHEADER_avilib *bitmap_info_header;
WAVEFORMATEX_avilib *wave_format_ex[AVI_MAX_TRACKS];
} avi_t;
#define AVI_MODE_WRITE 0
#define AVI_MODE_READ 1
/* The error codes delivered by avi_open_input_file */
#define AVI_ERR_SIZELIM 1 /* The write of the data would exceed
the maximum size of the AVI file.
This is more a warning than an error
since the file may be closed safely */
#define AVI_ERR_OPEN 2 /* Error opening the AVI file - wrong path
name or file nor readable/writable */
#define AVI_ERR_READ 3 /* Error reading from AVI File */
#define AVI_ERR_WRITE 4 /* Error writing to AVI File,
disk full ??? */
#define AVI_ERR_WRITE_INDEX 5 /* Could not write index to AVI file
during close, file may still be
usable */
#define AVI_ERR_CLOSE 6 /* Could not write header to AVI file
or not truncate the file during close,
file is most probably corrupted */
#define AVI_ERR_NOT_PERM 7 /* Operation not permitted:
trying to read from a file open
for writing or vice versa */
#define AVI_ERR_NO_MEM 8 /* malloc failed */
#define AVI_ERR_NO_AVI 9 /* Not an AVI file */
#define AVI_ERR_NO_HDRL 10 /* AVI file has no has no header list,
corrupted ??? */
#define AVI_ERR_NO_MOVI 11 /* AVI file has no has no MOVI list,
corrupted ??? */
#define AVI_ERR_NO_VIDS 12 /* AVI file contains no video data */
#define AVI_ERR_NO_IDX 13 /* The file has been opened with
getIndex==0, but an operation has been
performed that needs an index */
/* Possible Audio formats */
#ifndef WAVE_FORMAT_PCM
#define WAVE_FORMAT_UNKNOWN (0x0000)
#define WAVE_FORMAT_PCM (0x0001)
#define WAVE_FORMAT_ADPCM (0x0002)
#define WAVE_FORMAT_IBM_CVSD (0x0005)
#define WAVE_FORMAT_ALAW (0x0006)
#define WAVE_FORMAT_MULAW (0x0007)
#define WAVE_FORMAT_OKI_ADPCM (0x0010)
#define WAVE_FORMAT_DVI_ADPCM (0x0011)
#define WAVE_FORMAT_DIGISTD (0x0015)
#define WAVE_FORMAT_DIGIFIX (0x0016)
#define WAVE_FORMAT_YAMAHA_ADPCM (0x0020)
#define WAVE_FORMAT_DSP_TRUESPEECH (0x0022)
#define WAVE_FORMAT_GSM610 (0x0031)
#define IBM_FORMAT_MULAW (0x0101)
#define IBM_FORMAT_ALAW (0x0102)
#define IBM_FORMAT_ADPCM (0x0103)
#endif
avi_t *AVI_open_output_file(char *filename);
void AVI_set_video(avi_t *AVI, int width, int height, double fps, char *compressor);
void AVI_set_audio(avi_t *AVI, int channels, long rate, int bits, int format, long mp3rate);
void AVI_set_video_suggestbuffersize(avi_t *AVI, int suggestbuffersize);
int AVI_write_frame(avi_t *AVI, char *data, long bytes, int keyframe);
int AVI_dup_frame(avi_t *AVI);
int AVI_write_audio(avi_t *AVI, char *data, long bytes);
int AVI_append_audio(avi_t *AVI, char *data, long bytes);
long AVI_bytes_remain(avi_t *AVI);
int AVI_close(avi_t *AVI);
long AVI_bytes_written(avi_t *AVI);
avi_t *AVI_open_input_file(const char *filename, int getIndex);
avi_t *AVI_open_fd(int fd, int getIndex);
int avi_parse_input_file(avi_t *AVI, int getIndex);
long AVI_audio_mp3rate(avi_t *AVI);
long AVI_video_frames(avi_t *AVI);
int AVI_video_width(avi_t *AVI);
int AVI_video_height(avi_t *AVI);
double AVI_frame_rate(avi_t *AVI);
char *AVI_video_compressor(avi_t *AVI);
int AVI_audio_channels(avi_t *AVI);
int AVI_audio_bits(avi_t *AVI);
int AVI_audio_format(avi_t *AVI);
long AVI_audio_rate(avi_t *AVI);
long AVI_audio_bytes(avi_t *AVI);
long AVI_audio_chunks(avi_t *AVI);
long AVI_max_video_chunk(avi_t *AVI);
long AVI_frame_size(avi_t *AVI, long frame);
long AVI_audio_size(avi_t *AVI, long frame);
int AVI_seek_start(avi_t *AVI);
int AVI_set_video_position(avi_t *AVI, long frame);
long AVI_get_video_position(avi_t *AVI, long frame);
long AVI_read_frame(avi_t *AVI, char *vidbuf, int *keyframe);
int AVI_set_audio_position(avi_t *AVI, long byte);
int AVI_set_audio_bitrate(avi_t *AVI, long bitrate);
long AVI_read_audio(avi_t *AVI, char *audbuf, long bytes);
long AVI_read_audio_chunk(avi_t *AVI, char *audbuf);
long AVI_audio_codech_offset(avi_t *AVI);
long AVI_audio_codecf_offset(avi_t *AVI);
long AVI_video_codech_offset(avi_t *AVI);
long AVI_video_codecf_offset(avi_t *AVI);
int AVI_read_data(avi_t *AVI, char *vidbuf, long max_vidbuf,
char *audbuf, long max_audbuf,
long *len);
void AVI_print_error(char *str);
char *AVI_strerror();
char *AVI_syserror();
int AVI_scan(char *name);
int AVI_dump(char *name, int mode);
char *AVI_codec2str(short cc);
int AVI_file_check(char *import_file);
void AVI_info(avi_t *avifile);
uint64_t AVI_max_size();
int avi_update_header(avi_t *AVI);
int AVI_set_audio_track(avi_t *AVI, int track);
int AVI_get_audio_track(avi_t *AVI);
int AVI_audio_tracks(avi_t *AVI);
struct riff_struct {
unsigned char id[4]; /* RIFF */
uint32_t len;
unsigned char wave_id[4]; /* WAVE */
};
struct chunk_struct {
unsigned char id[4];
uint32_t len;
};
struct common_struct {
uint16_t wFormatTag;
uint16_t wChannels;
uint32_t dwSamplesPerSec;
uint32_t dwAvgBytesPerSec;
uint16_t wBlockAlign;
uint16_t wBitsPerSample; /* Only for PCM */
};
struct wave_header {
struct riff_struct riff;
struct chunk_struct format;
struct common_struct common;
struct chunk_struct data;
};
struct AVIStreamHeader {
long fccType;
long fccHandler;
long dwFlags;
long dwPriority;
long dwInitialFrames;
long dwScale;
long dwRate;
long dwStart;
long dwLength;
long dwSuggestedBufferSize;
long dwQuality;
long dwSampleSize;
};
#endif
File diff suppressed because it is too large Load Diff
+310
View File
@@ -0,0 +1,310 @@
#ifndef __AVI_VIDEO_
#define __AVI_VIDEO_
#include "app_config.h"
#include "cpu.h"
#include "fs/fs.h"
#include "app_config.h"
#include "board_config.h"
#include "generic/circular_buf.h"
#include "app_config.h"
#include "asm/audio_adc.h"
#include "generic/circular_buf.h"
#include "media/audio_decoder.h"
#include "media/mixer.h"
#include "generic/log.h"
#include "app_config.h"
#include "system/timer.h"
#include "device/device.h"
#include "key_event_deal.h"
#include "res/resfile.h"
#include "jlui/ui.h"
#include "jlui_app/ui_style.h"
#include "jlui_app/ui_api.h"
#include "jlui_app/res_config.h"
#include "jlui_app/ui_resource.h"
#include "jlui_app/ui_sys_param.h"
#include "timer.h" // 定时器
#include "ui/lcd/lcd_drive.h" // lcd 驱动
#include "res_config.h" // res 文件管理
#include <math.h>
#include "ascii.h"
#include "res/font_ascii.h"
#include "res/mem_var.h"
#include "res/zz.h"
#include "res/jpeg_decoder.h"
#include "dev_manager.h"
#include "fs/fs.h"
#include "watch_syscfg_manage.h"
#include "ui_core.h"
#include "control.h"
#include "dbi.h" // 推屏模块
#include "jlgpu_math.h" // matrix
#include "jlgpu_driver.h" // gpu 驱动
#include "gpu_port.h" // GPU 接口,依赖于 jlgpu_driver.h
#include "gpu_task.h"
#include "ui_resource.h" // ui资源管理
#include "jlui_effect/jlui_effect.h" //特效相关
#include "ui_expand/buffer_manager.h" // buffer管理
#include "ui_expand/ui_expand.h" // 部分宏定义
#include "font/font_all.h"
#include "font/font_textout.h"
#include "ui_draw/ui_circle.h"
#include "ui_animation.h"
#include "font/language_list.h"
#include "ui_measure.h"
#include "jljpeg_decode.h"
#include "gpu_draw.h"
#include "ui_page_switch.h"
#include "ui_draw/ui_basic.h"
#include "ui_text.h"
#include "jlui_app/ui_style.h"
#include "res/resfile.h"
#include "media/includes.h"
#include "audio_config.h"
#include "gpio.h"
typedef void (*ChunkCallback)(FILE *file,
off_t chunk_offset,
const char *chunk_id,
uint32_t chunk_size,
const char *list_name,
const char **hierarchy,
int level,
int *jump,
void *user_param);
#pragma pack(push, 1)
typedef struct {
uint32_t dwMicroSecPerFrame; // 每帧时长(微秒)
uint32_t dwMaxBytesPerSec; // 最大字节/秒(数据传输率)
uint32_t dwPaddingGranularity;// 数据填充粒度(单位字节)
uint32_t dwFlags; // 全局标志(如索引存在性)
uint32_t dwTotalFrames; // 总帧数
uint32_t dwInitialFrames; // 初始帧数(用于交错格式)
uint32_t dwStreams; // 流数量(如视频、音频)
uint32_t dwSuggestedBufferSize; // 建议缓冲区大小
uint32_t dwWidth; // 视频宽度(像素)
uint32_t dwHeight; // 视频高度(像素)
uint32_t dwReserved[4]; // 保留字段(必须为0
} AVIH_Header;
// 流头结构(strh
typedef struct {
char fccType[4]; // 流类型 'vids'或'auds'
char fccHandler[4]; // 编码类型
uint32_t dwFlags; // 标志位
uint16_t wPriority; // 优先级
uint16_t wLanguage; // 语言
uint32_t dwInitialFrames; // 初始帧数
uint32_t dwScale; // 时间刻度
uint32_t dwRate; // 每秒采样数
uint32_t dwStart; // 开始时间
uint32_t dwLength; // 流长度
uint32_t dwSuggestedBufferSize;
uint32_t dwQuality;
uint32_t dwSampleSize; // 样本大小
} StreamHeader;
// 视频格式结构(strf
typedef struct {
uint32_t biSize; // 结构体大小
uint32_t biWidth; // 视频宽度
uint32_t biHeight; // 视频高度
uint16_t biPlanes; // 颜色平面数
uint16_t biBitCount; // 每像素位数
uint32_t biCompression; // 压缩类型
uint32_t biSizeImage; // 图像数据大小
} VideoFormat;
// 音频格式结构(strf
typedef struct {
uint16_t wFormatTag; // 格式类型
uint16_t nChannels; // 声道数
uint32_t nSamplesPerSec; // 采样率
uint32_t nAvgBytesPerSec; // 平均字节率
uint16_t nBlockAlign; // 块对齐
uint16_t wBitsPerSample; // 位深
} AudioFormat;
typedef struct {
u32 time; // jpeg 最新更新时间
jdec_opj *opj; // jpeg 句柄
int pos; // 相对文件位置
int len; // 单个JPEG长度
u8 *data;
} mjpegdata;
typedef struct {
int block_len; // 最大的jpeg 长度
int cnt; // 缓存数量
int act_idx; // 当前正在忙的缓存
int pre_idx;
mjpegdata *m;
u8 *data; //所有jpeg+信息数据
} cachebuf;
#pragma pack(pop) // 恢复内存对齐
typedef enum {
STREAM_NULL,
STREAM_VIDEO,
STREAM_AUDIO
} StreamType;
typedef struct {
// 文件信息
FILE *file;
int movi_data_start; // movi列表区起始位置(movi字符前)
size_t movi_data_len; //(包括movi字符)
int idx1_offset; // idx1块起始偏移
size_t idx1_size; // idx1块数据大小
AVIH_Header avih_header;
// 流头状态机
StreamType stream_type;
StreamHeader video_stream_header;
VideoFormat video_format;
StreamHeader audio_stream_header;
AudioFormat audio_format;
// 视频信息
int width;
int height;
int frame_rate;
uint32_t total_frames;
uint64_t total_duration;
// 音频信息
int sample_rate;
int channels;
int bits_per_sample;
u8 auds_vol;
u8 auds_drop;
int auds_idx;
u8 auds_exit;
u16 auds_inr;
int auds_rate;
int auds_total;
char *auds_frame;
cbuffer_t auds_cbuf;
// 播放状态
int current_pos;
int is_playing;
int lv_pos;
int lv_size;
cachebuf cache;
int timerid;
int redrawid;
u8 ui_work;
unsigned long jump_mjpeg;
// MyReadHandle frhandle; // fread缓冲
int now_offset; // 在文件的偏移
int now_len; // 块长度
struct flash_file_info *view_file_info;
OS_MUTEX mutex;
struct audio_dac_hdl ad;
uint8_t buf_ok;
} AVIPlayer;
void *avi_open(const char *path, int en_buf, int redrawid);
void avi_close(void *avip);
int avi_fluh(void *priv);
typedef struct {
void *fp;
char fname[64];
OS_SEM mv_sem;
void *st; // 解码器
int drawid;
int act; // -1: 销毁 0:关闭解码器 1:活跃
u8 pause;
u8 repeat;
u8 type;
u8 avi_audio_start;
u8 avi_play_mode;
u8 avi_is_switching;
u8 avi_index;
u16 avi_playtimer;
int start;
int time;
int frameCount;
int flushTimer;
int avi_now_idx;
u8 *avi_pcm_buf;
long file_offset;
} MV_DRAW;
void __jpeg_draw_cb_gpu(int id, u8 *dst_buf, struct rect *dst_r, struct rect *src_r, u8 bytes_per_pixel, void *priv, void *matrix);
void avi_pcm_open(void *avip);
void avi_pcm_close(void *avip) ;
// 0918新增内容
const char *set_avi_play_file(void);
void avi_play_next(void);
void avi_play_prev(void);
void avi_play_shutdown(void);
void set_avi_play_mode(u8 mode);
int avi_get_width(void *avip);
int avi_get_height(void *avip);
void *avi_get_fp(void *avip);
int avi_get_now_len(void *avip);
int avi_get_now_offset(void *avip);
int avi_get_mjpegbuflen(void *avip);
int avi_get_redrawid(void *avip);
float avi_get_total_sec(void *avip);
void *avi_get_view_file_info(void *priv);
void *animig_open(char *name, int window_id, int arg);
void avi_set_avi_playtimer_id(u16 timer_id);
u16 avi_get_avi_playtimer_id();
void *get_aviplay_handle();
void *get_avi_player_st_handle();
#define AVI_WINDOW PAGE_77
#define AVI_LAYOUT AVI_DEMO_LAYOUT
#endif
@@ -0,0 +1,287 @@
#include "camera_manager.h"
#include "bf30a2_cfg.h"
#include "iic_api.h"
#if TCFG_CAMERA_DEV_BF30A2
static const struct reginfo sensor_init_data[] = {
0xf2, 0x01, //软复位
0x15, 0x80,
0x6b, 0x73,
0x04, 0x00,
0x06, 0x26,
0x08, 0x07,
0x1c, 0x12,
0x1e, 0x26,
0x1f, 0x01,
0x20, 0x20,
0x21, 0x20,
0x34, 0x02,
0x35, 0x02,
0x36, 0x21,
0x37, 0x13,
#if (BF30A2_INPUT_FPS == 15)
0xca, 0x02, //15ps
#else
0xca, 0x03, //30ps
#endif
0x17, START_ADDRW,
0x18, END_ADDRW,
0x19, START_ADDRH,
0x1a, (END_ADDRH >> 1) & 0xFF,
0x12, 0x10 | ((END_ADDRH & 0x1) << 7),
/* 0xcf, 0x90, */
0xcf, 0x05,
0xcb, 0x22,
0xcc, 0x89,
0xcd, 0x4c,
0xce, 0x6b,
0xa0, 0x8e,
0x01, 0x1b,
0x02, 0x1d,
0x13, 0x08,
0x87, 0x13,
0x8a, 0x33,
0x8b, 0x08,
0x70, 0x1f,
0x71, 0x40,
0x72, 0x0a,
0x73, 0x62,
0x74, 0xa2,
0x75, 0xbf,
0x76, 0x02,
0x77, 0xcc,
0x40, 0x32,
0x41, 0x28,
0x42, 0x26,
0x43, 0x1d,
0x44, 0x1a,
0x45, 0x14,
0x46, 0x11,
0x47, 0x0f,
0x48, 0x0e,
0x49, 0x0d,
0x4B, 0x0c,
0x4C, 0x0b,
0x4E, 0x0a,
0x4F, 0x09,
0x50, 0x09,
0x24, 0x50,
0x25, 0x36,
0x80, 0x00,
0x81, 0x20,
0x82, 0x40,
0x83, 0x30,
0x84, 0x50,
0x85, 0x30,
0x86, 0xD8,
0x89, 0x45,
0x8f, 0x81,
0x91, 0xff,
0x92, 0x08,
0x94, 0x82,
0x95, 0xfd,
0x9a, 0x20,
0x9e, 0xbc,
0xf0, 0x83,//动态帧率关闭 0x8f 打开 0x83关
0x51, 0x06,
0x52, 0x25,
0x53, 0x2b,
0x54, 0x0F,
0x57, 0x2A,
0x58, 0x22,
0x59, 0x2c,
0x23, 0x33,
0xa0, 0x8f,
0xa1, 0x93,
0xa2, 0x0f,
0xa3, 0x2a,
0xa4, 0x08,
0xa5, 0x26,
0xa7, 0x80,
0xa8, 0x80,
0xa9, 0x1e,
0xaa, 0x19,
0xab, 0x18,
0xae, 0x50,
0xaf, 0x04,
0xc8, 0x10,
0xc9, 0x15,
0xd3, 0x0c,
0xd4, 0x16,
0xee, 0x06,
0xef, 0x04,
0x55, 0x34,
0x56, 0x9c,
0xb1, 0x98,
0xb2, 0x98,
0xb3, 0xc4,
0xb4, 0x0C,
0x00, 0x40,
0x13, 0x07,
};
static u8 read_bf30a2_reg(u8 reg_id)
{
u8 data = 0;
iic_start(IIC_ID);
iic_tx_byte(IIC_ID, BF30A2_WRCMD);
delay_nops(DELAY_TIME);
iic_tx_byte(IIC_ID, reg_id);
delay_nops(DELAY_TIME);
iic_stop(IIC_ID);
delay_nops(DELAY_TIME);
iic_start(IIC_ID);
delay_nops(DELAY_TIME);
iic_tx_byte(IIC_ID, BF30A2_RDCMD);
delay_nops(DELAY_TIME);
data = iic_rx_byte(IIC_ID, 0, NULL);
delay_nops(DELAY_TIME);
iic_stop(IIC_ID);
return data;
}
static void write_bf30a2_reg(u8 reg_id, u8 data)
{
iic_start(IIC_ID);
iic_tx_byte(IIC_ID, BF30A2_WRCMD);
delay_nops(DELAY_TIME);
iic_tx_byte(IIC_ID, reg_id);
delay_nops(DELAY_TIME);
iic_tx_byte(IIC_ID, data);
delay_nops(DELAY_TIME);
iic_stop(IIC_ID);
}
int bf30a2_check(void)
{
int ret = -1;
u16 pid = 0x00;
u8 id0, id1;
id0 = read_bf30a2_reg(0xfc);
id1 = read_bf30a2_reg(0xfd);
pid = (u16)((id0 << 8) | id1);
printf("BF30A2 Sensor ID : 0x%x\n", pid);
if (pid == 0x3b02) {
ret = 0;
}
return ret;
}
int bf30a2_dev_check(void)
{
int ret = -1;
bf30a2_io_init();
os_time_dly(2);
ret = bf30a2_check();
bf30a2_io_exit();
return ret;
}
void bf30a2_config_sensor(void)
{
int i;
for (i = 0; i < ARRAY_SIZE(sensor_init_data); i++) {
write_bf30a2_reg(sensor_init_data[i].reg, sensor_init_data[i].val);
}
}
void bf30a2_out_sleep(void)
{
write_bf30a2_reg(0xcf, 0x90);
}
void bf30a2_in_sleep(void)
{
write_bf30a2_reg(0xcf, 0x05);
}
int bf30a2_io_init(void)
{
// I2C INIT
hw_iic_dev iic_dev = IIC_ID;
struct iic_master_config iic_config = {
.role = IIC_MASTER,
.scl_io = IIC_SCL_IO,
.sda_io = IIC_SDA_IO,
.io_mode = PORT_INPUT_PULLUP_10K,//上拉或浮空
.hdrive = PORT_DRIVE_STRENGT_2p4mA, //enum GPIO_HDRIVE 0:2.4MA, 1:8MA, 2:26.4MA, 3:40MA
.master_frequency = 50,
};
enum iic_state_enum iic_init_state = iic_init(iic_dev, &iic_config);
if (iic_init_state != IIC_OK) {
printf("iic(%d) master init fail", iic_dev);
return -1;
}
//XCLK
clk_out(SPI_XCLK_PORT, CLK_OUT_STD_24M, 0);
//PWR IO
gpio_set_mode(IO_PORT_SPILT(CAM_PWR_IO), PORT_OUTPUT_HIGH);
return 0;
}
int bf30a2_camera_init(void)
{
if (bf30a2_io_init()) {
printf("------- bf30a2 io init fail------\n\n");
return -1;
}
os_time_dly(2);
if (bf30a2_check()) {
printf("-------not bf30a2 camera------\n\n");
return -1;
}
printf("-------hello bf30a2 camera------\n\n");
bf30a2_config_sensor();
return 0;
}
int bf30a2_io_exit(void)
{
// I2C
hw_iic_dev iic_dev = IIC_ID;
enum iic_state_enum iic_init_state = iic_deinit(iic_dev);
if (iic_init_state != IIC_OK) {
printf("iic(%d) master deinit fail", iic_dev);
return -1;
}
//XCLK
clk_out_close(SPI_XCLK_PORT, CLK_OUT_STD_24M);
//PWR IO
gpio_set_mode(IO_PORT_SPILT(CAM_PWR_IO), PORT_OUTPUT_LOW);
return 0;
}
int bf30a2_camera_exit(void)
{
if (bf30a2_io_exit()) {
printf("------ bf30a2 io deinit fail------\n\n");
return -1;
}
return 0;
}
REGISTER_CAMERA_DEVICE(bf30a2_cfg)
{
.fps = BF30A2_INPUT_FPS,
.width = BF30A2_INPUT_W,
.height = BF30A2_INPUT_H,
.check = bf30a2_dev_check,
.init = bf30a2_camera_init,
.deinit = bf30a2_camera_exit,
.supend = bf30a2_in_sleep,
.resume = bf30a2_out_sleep,
};
#endif
@@ -0,0 +1,45 @@
#ifndef BF30A2_CFG_H
#define BF30A2_CFG_H
#include "system/includes.h"
//分辨率设置
#define BF30A2_INPUT_W 240 //摄像头图像宽
#define BF30A2_INPUT_H 320 //摄像头图像高
//根据帧率调整SPI PCLK 15->12M 30->24M
#define BF30A2_INPUT_FPS 30 //(摄像头实际帧率只有此设置值的一半)帧率
//摄像头裁剪窗口
#define START_ADDRW 0
#define START_ADDRH 0
#define END_ADDRW (BF30A2_INPUT_W + START_ADDRW)
#define END_ADDRH (BF30A2_INPUT_H + START_ADDRH)
//IIC
#define IIC_ID 2 //IIC ID号
#define IIC_SCL_IO IO_PORTC_03 //IIC SCL
#define IIC_SDA_IO IO_PORTC_10 //IIC SDA
#define DELAY_TIME 10 //IIC 延时
#define BF30A2_WRCMD 0xdc //摄像头IIC写地址
#define BF30A2_RDCMD 0xdd //摄像头IIC读地址
//IO
#define CAM_PWR_IO IO_PORTC_11 //摄像头电源提供
#define SPI_XCLK_PORT IO_PORTC_00 //摄像头时钟提供
struct reginfo {
u8 reg;
u8 val;
};
int bf30a2_check(void);
void bf30a2_config_sensor(void);
void bf30a2_out_sleep(void);
void bf30a2_in_sleep(void);
int bf30a2_io_init(void);
int bf30a2_io_exit(void);
#endif /* BF30A2_CFG_H */
@@ -0,0 +1,547 @@
#include "system/includes.h"
#include "app_config.h"
#include "software_jpegenc.h"
#include "spi.h"
#include "generic/lbuf.h"
#include "camera_queue_buf.h"
#include "camera_manager.h"
#include "bf30a2_cfg.h"
#include "avilib.h"
#include "asm/dma_copy.h"
#define LOG_TAG_CONST CAMERA_MANAGER
#define LOG_TAG "[CAMERA_MANAGER]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
#define LOG_CHAR_ENABLE //log_char enable
#define LOG_CLI_ENABLE
#include "debug.h"
#define offsetof(type, memb) \
((unsigned long)(&((type *)0)->memb))
// SPI
#define SPI_FEND_SIZE 4 // 包头
#define SPI_LEND_SIZE 4 // 包尾
#define SPI_FHEAD_SIZE 4 // 行头
#define SPI_LHEAD_SIZE 4 // 行尾
#define SPI_ID HW_SPI1 // SPI ID号,spi2可能用于nandflash
#define QBUF_EXT_SIZE 4//qbuf拓展数据
// 接收队列BUF总大小 DMA_REVC_SIZE * DMA_REVC_BUF_NUM
#define INPUT_WIDTH 240
#define OUTPUT_HEIGHT 320
#define DMA_LINE_SIZE ( INPUT_WIDTH* 2 + SPI_FHEAD_SIZE + SPI_LHEAD_SIZE) // 摄像头一行大小 格式:YUVY
#define DMA_CAMERA_SIZE (16) // 一次SPI DMA接收的行数
#define DMA_REVC_SIZE (DMA_LINE_SIZE * DMA_CAMERA_SIZE + SPI_FEND_SIZE) // 一次SPI DMA接收的大小,帧头、帧尾会多四个字节
#define DMA_REVC_BUF_NUM (20) // 接收BUF的数量
// JPEG缓存
#define JPEG_LBUF_SIZE (100 * 1024) // LBUF总大小,编码出的jpeg存放在lbuf中
#define ONE_JPEG_MAX_SIZE (10 * 1024) // 单张JPEG的大小,申请LBUF缓存时用到,可根据情况调整
#define JPEG_QVAL 50 // jpeg编码默认Q值(0-100)
enum {
SPI_NEW_CHUNK = 1,
SPI_DROP_FRAME,
JPEG_TASK_KILL,
};
struct lbuf_data_head {
int len;
u8 data[0];
};
struct camera_handle {
//设备驱动
struct camera_device *dev;
// JPEG 编码线程
char task_name[32];
u8 task_runing;
OS_SEM task_kill_sem;
// SPI接收行数统计
int spi_recv_line_cnt;
// jpeg lbuf
u8 *lbuf_ptr;
struct lbuff_head *lbuf_handle;
// yuv buf 队列
struct queue_buf *qbuf;
// SPI DMA 接收buf,中转buf,接收完后拷贝到队列buf
u8 *dma_recv_buf[2];
int dma_recv_buf_index;
};
static struct camera_handle *camera_hdl;
#define __this (camera_hdl)
AT(.spi.text.cache.L1)
__attribute__((interrupt("")))
static void camera_hw_spi_isr()
{
/*
在不可屏蔽中断调用,此函数及调用的子函数均需要放ram
特别注意打印。
否则在写flash的时候,会触发死机
*/
JL_SPI_TypeDef *SPI_REG = (SPI_ID == HW_SPI1) ? JL_SPI1 : JL_SPI2;
//clr pnd
SPI_REG->CON |= BIT(14);
if (SPI_REG->CON & BIT(21)) {
// slave rx dma overflow
SPI_REG->CON &= ~BIT(20); // clr
/* log_char('O'); */
}
if (SPI_REG->CON & BIT(18)) {
// slave tx dma underflow
SPI_REG->CON &= ~BIT(17); // clr
/* log_char('U'); */
}
// dma copy buf
u8 *recv_done_buf = __this->dma_recv_buf[__this->dma_recv_buf_index];
u8 *chunk = queue_buf_get_isr(__this->qbuf);
if (chunk) {
dma_memcpy_async_inirq(chunk, recv_done_buf, DMA_REVC_SIZE);
//标记行号
chunk[DMA_REVC_SIZE + 0] = 0x55;
chunk[DMA_REVC_SIZE + 1] = 0xaa;
u16 *chunk_rec_line = (u16 *)&chunk[DMA_REVC_SIZE + 2];
*chunk_rec_line = __this->spi_recv_line_cnt;
queue_buf_push_isr(__this->qbuf);
}
/* memcpy(chunk, recv_done_buf, DMA_REVC_SIZE); */
__this->dma_recv_buf_index = (__this->dma_recv_buf_index + 1) % ARRAY_SIZE(__this->dma_recv_buf);
__this->spi_recv_line_cnt = (DMA_CAMERA_SIZE + __this->spi_recv_line_cnt) % (__this->dev->height);
// 帧中间,减去帧头or帧尾的长度
u32 recv_cnt = DMA_REVC_SIZE - SPI_LEND_SIZE;
if (__this->spi_recv_line_cnt == 0 || __this->spi_recv_line_cnt == (__this->dev->height - DMA_CAMERA_SIZE)) {
recv_cnt = DMA_REVC_SIZE;
}
u8 *buf = __this->dma_recv_buf[__this->dma_recv_buf_index];
SPI_REG->CON |= BIT(12);
SPI_REG->ADR = (u32)buf;
SPI_REG->CNT = recv_cnt;
}
static void camera_jpeg_dec_task(void *priv)
{
log_debug("%s enter>>>>>>>>>>>>>>>>>!\n", __func__);
struct camera_handle *hdl = (struct camera_handle *)priv;
u8 jpeg_qval = JPEG_QVAL;
log_debug("%s dev:%x", __func__, (u32)__this->dev);
void *jpegenc_hdl = software_jpegenc_init(
__this->dev->width,
__this->dev->height,
__this->dev->width + SPI_FHEAD_SIZE,
jpeg_qval);
if (!jpegenc_hdl) {
log_error("software jpegenc init err \n");
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
struct lbuf_data_head *lbuf_data = NULL;
int ret = 0;
int jpeg_buf_size = ONE_JPEG_MAX_SIZE;
int line_cnt = 0;
u8 *cur_bits = NULL;
int total_bits = 0;
u8 fps = 0;
u32 fps_time = jiffies_msec();
u32 enc_time;
while (hdl->task_runing) {
u8 *chunk = NULL;
/* dma_memcpy_wait_idle(); */
chunk = queue_buf_pop(__this->qbuf);
if (!chunk) {//pass
log_char('P');
os_time_dly(1);
continue;
}
if ((chunk[DMA_REVC_SIZE + 0]) == 0x55 && (chunk[DMA_REVC_SIZE + 1] == 0xaa)) {
u16 *chunk_rec_line = (u16 *)&chunk[DMA_REVC_SIZE + 2];
if (*chunk_rec_line == line_cnt) {
//正常执行
} else {
//pass当前帧
queue_buf_reset(__this->qbuf);
line_cnt = 0;
log_warn("pop[c:%d l:%d]", (*chunk_rec_line), line_cnt);
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
os_time_dly(1);
continue;
}
}
} else {
log_error("%s line_cnt:%d", __func__, line_cnt);
put_buf(chunk + DMA_CAMERA_SIZE, 4);
}
//帧首,申请jpeg lbuf
if (line_cnt == 0) {
while (!lbuf_data) {
lbuf_data = lbuf_alloc(__this->lbuf_handle, jpeg_buf_size);
if (!lbuf_data) {
log_char('L');
lbuf_data = lbuf_pop(__this->lbuf_handle, BIT(0));
if (lbuf_data) {
lbuf_free(lbuf_data);
lbuf_data = NULL;
}
continue;
}
}
total_bits = 0;
enc_time = jiffies_msec();
}
cur_bits = lbuf_data->data + total_bits;
int remain_size = jpeg_buf_size - total_bits;
int out_bits_size = 0;
u8 *in_buf = line_cnt ? chunk + SPI_FHEAD_SIZE :
chunk + SPI_FHEAD_SIZE + SPI_LHEAD_SIZE;
if (software_jpegenc_line(jpegenc_hdl, cur_bits, remain_size,
in_buf, DMA_CAMERA_SIZE, line_cnt, &out_bits_size)) {
log_error("software jpgenc line err \n");
continue;
}
total_bits += out_bits_size;
line_cnt += DMA_CAMERA_SIZE;
queue_buf_release(__this->qbuf);
//帧尾 push jpeg_buf
if (line_cnt == __this->dev->height) {
lbuf_data->len = total_bits;
lbuf_push(lbuf_data, BIT(0));
lbuf_data = NULL;
line_cnt = 0;
//fps info
fps++;
if ((jiffies_msec() - fps_time) > 1000) {
log_info("jpeg fps:%d enc_time:%lu \n", fps, jiffies_msec() - enc_time);
fps = 0;
fps_time = jiffies_msec();
}
}
}
log_debug("%s exit>>>>>>>>>>>>>>>>!\n", __func__);
software_jpegenc_exit(jpegenc_hdl);
//下面禁止加打印{
os_sem_post(&__this->task_kill_sem);
os_time_dly(-1);
//}
}
int camera_spi_init()
{
int ret = 0;
hw_spi_dev spi = SPI_ID;
struct spi_platform_data spix_p_data = {
.port = {
IO_PORTC_01, // clk any io
IO_PORTC_02, // do any io
IO_PORTC_02, // di any io
0xff, // d2 any io
0xff, // d3 any io
0xff, // cs any io(主机不操作cs)
},
.role = SPI_ROLE_SLAVE,
.mode = SPI_MODE_BIDIR_1BIT, // SPI_MODE_UNIDIR_2BIT,//SPI_MODE_BIDIR_1BIT,
.bit_mode = SPI_FIRST_BIT_MSB,
.cpol = 0, // clk level in idle state:0:low, 1:high
.cpha = 0, // sampling edge:0:first, 1:second
.ie_en = 0, // ie enbale:0:disable, 1:enable
.irq_priority = 3,
.spi_isr_callback = NULL,
.clk = 24000000L,
};
ret = spi_open(spi, &spix_p_data);
if (ret < 0) {
log_error("spi master init error(%d)!", ret);
return ret;
}
spi_set_ie(spi, 1);
if (spi == HW_SPI1) {
request_irq(IRQ_SPI1_IDX, 7, camera_hw_spi_isr, 0);
irq_unmask_set(IRQ_SPI1_IDX, 0, 0);
} else {
request_irq(IRQ_SPI2_IDX, 7, camera_hw_spi_isr, 0);
irq_unmask_set(IRQ_SPI2_IDX, 0, 0);
}
os_time_dly(2);
u8 *buf = __this->dma_recv_buf[0];
spi_dma_transmit_for_isr(spi, (void *)buf, DMA_REVC_SIZE, 1);
return 0;
}
int camera_spi_deinit()
{
hw_spi_dev spi = SPI_ID;
spi_deinit(spi);
return 0;
}
int camera_manager_start(void)
{
int ret = 0;
mem_stats();
struct camera_device *dev = __this->dev;
memset(__this, 0x00, sizeof(struct camera_handle));
__this->dev = dev;
__this->qbuf = queue_buf_create(DMA_REVC_SIZE + QBUF_EXT_SIZE, DMA_REVC_BUF_NUM);
if (!__this->qbuf) {
return -1;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
__this->dma_recv_buf[i] = malloc(DMA_REVC_SIZE);
if (!__this->dma_recv_buf[i]) {
log_error("dma recv buf malloc fail \n");
goto __err;
}
}
__this->lbuf_ptr = malloc_psram(JPEG_LBUF_SIZE);
if (!__this->lbuf_ptr) {
log_error("jpeg lbuf_ptr malloc fail \n");
goto __err;
}
__this->lbuf_handle = lbuf_init(__this->lbuf_ptr, JPEG_LBUF_SIZE, 4, sizeof(struct lbuf_data_head));
os_sem_create(&__this->task_kill_sem, 0);
__this->task_runing = 1;
snprintf(__this->task_name, sizeof(__this->task_name), "camera_jpeg_task");
if (os_task_create(camera_jpeg_dec_task, __this, 10, 1024, 1024, __this->task_name)) {
log_error(" read task create fail \n");
__this->task_runing = 0;
goto __err;
}
if (camera_spi_init()) {
goto __err;
}
camera_manager_resume();
return 0;
__err:
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
}
if (__this->lbuf_ptr) {
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return -1;
}
int camera_manager_stop(void)
{
printf("%s %d", __func__, __LINE__);
camera_manager_suspend();
camera_spi_deinit();
if (__this->task_runing) {
__this->task_runing = 0;
os_sem_pend(&__this->task_kill_sem, 0);
os_sem_del(&__this->task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->task_name);
}
if (__this->qbuf) {
queue_buf_destroy(__this->qbuf);
__this->qbuf = NULL;
}
if (__this->lbuf_ptr) {
free_psram(__this->lbuf_ptr);
__this->lbuf_ptr = NULL;
}
for (int i = 0; i < ARRAY_SIZE(__this->dma_recv_buf); i++) {
if (__this->dma_recv_buf[i]) {
free(__this->dma_recv_buf[i]);
__this->dma_recv_buf[i] = NULL;
}
}
return 0;
}
void camera_manager_resume(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
if (!__this->dev->resume) {
return ;
}
__this->dev->resume();
}
void camera_manager_suspend(void)
{
if (!__this) {
return ;
}
if (!__this->dev) {
return ;
}
if (!__this->dev->supend) {
return ;
}
__this->dev->supend();
}
static int camera_manager_dev_check(void)
{
struct camera_device *dev = NULL;
list_for_each_camera_device_module(dev) {
if (dev->check) {
if (!dev->check()) {
log_debug("%s find device:%x\n", __func__, (u32)dev);
__this->dev = dev;
return 0;
}
}
}
return -1;
}
int camera_manager_init(void)
{
ASSERT(!__this);
__this = malloc(sizeof(struct camera_handle));
camera_manager_dev_check();
if (!__this->dev) {
return -1;
}
if (!__this->dev->init) {
return -1;
}
return __this->dev->init();
}
int camera_manager_deinit(void)
{
if (!__this) {
return -1;
}
if (!__this->dev) {
return -1;
}
if (!__this->dev->deinit) {
return -1;
}
int ret = __this->dev->deinit();
free(__this);
__this = NULL;
return ret;
}
int camera_manager_data_read(u8 **pp_data, int *p_len)
{
struct lbuf_data_head *node;
if (!pp_data || !p_len) {
log_error("camera read ptr err \n");
return -1;
}
node = lbuf_pop(__this->lbuf_handle, BIT(0));
if (!node) {
return -2;
}
*pp_data = node->data;
*p_len = node->len;
return 0;
}
int camera_manager_read_done(u8 *data_buf)
{
struct lbuf_data_head *node;
if (!data_buf) {
log_error("camera read done ptr err \n");
return -1;
}
node = (struct lbuf_data_head *)((u8 *)data_buf - offsetof(struct lbuf_data_head, data));
lbuf_free(node);
return 0;
}
int camera_manager_get_dev_width_height(int *width, int *height)
{
if (__this && __this->dev) {
*width = __this->dev->width;
*height = __this->dev->height;
return 0;
}
return -1;
}
int camera_manager_get_dev_fps(int *fps)
{
if (__this && __this->dev) {
*fps = __this->dev->fps;
return 0;
}
return -1;
}
@@ -0,0 +1,41 @@
#ifndef __CAMERA_MANAGER__
#define __CAMERA_MANAGER__
#include "app_config.h"
struct camera_device {
u8 fps;
u16 width;
u16 height;
int (*check)(void);
int (*init)(void);
int (*deinit)(void);
void (*supend)(void);
void (*resume)(void);
};
#define REGISTER_CAMERA_DEVICE(dev) \
const struct camera_device camera_device_##dev sec(.camera_device) =
extern const struct camera_device camera_device_module_begin[];
extern const struct camera_device camera_device_module_end[];
#define list_for_each_camera_device_module(p) \
for (p =(struct camera_device*)camera_device_module_begin; p < (struct camera_device*)camera_device_module_end; p++)
int camera_manager_start(void);
int camera_manager_stop(void);
void camera_manager_resume(void);
void camera_manager_suspend(void);
int camera_manager_init(void);
int camera_manager_deinit(void);
int camera_manager_data_read(u8 **pp_data, int *p_len);
int camera_manager_read_done(u8 *data_buf);
int camera_manager_get_dev_width_height(int *width, int *height);
int camera_manager_get_dev_fps(int *fps);
#endif//__CAMERA_MANAGER__
@@ -0,0 +1,115 @@
#include "camera_queue_buf.h"
#include "app_config.h"
//SPI传输数据量大的时候不能使用psram作为SPI DMA的地址,psram速度不够会导致异常
#if TCFG_PSRAM_DEV_ENABLE
#define malloc(size) malloc_psram(size)
#define free(ptr) free_psram(ptr)
#else
#define malloc(size) malloc(size)
#define free(ptr) free(ptr)
#endif
struct queue_buf *queue_buf_create(int buf_size, int capacity)
{
if (capacity <= 0 || buf_size <= 0) {
printf(NULL, "queue create fail cap or size <= 0 \n");
return NULL;
}
struct queue_buf *q = malloc(sizeof(struct queue_buf));
if (!q) {
printf("queue create fail malloc err \n");
return NULL;
}
memset(q, 0x00, sizeof(struct queue_buf));
q->buffer = malloc(capacity * sizeof(u8 *));
if (!q->buffer) {
printf("queue create fail malloc err \n");
goto err;
}
memset(q->buffer, 0x00, capacity * sizeof(u8 *));
for (int i = 0; i < capacity; i++) {
q->buffer[i] = malloc(buf_size);
if (!q->buffer[i]) {
printf("queue create fail malloc err \n");
goto err;
}
}
q->capacity = capacity;
q->buf_size = buf_size;
return q;
err:
if (q) {
if (q->buffer) {
for (int i = 0; i < capacity; i++) {
if (q->buffer[i]) {
free(q->buffer[i]);
}
}
free(q->buffer);
}
free(q);
}
return NULL;
}
void queue_buf_destroy(struct queue_buf *q)
{
if (q) {
if (q->buffer) {
for (int i = 0; i < q->capacity; i++) {
if (q->buffer[i]) {
free(q->buffer[i]);
} else {
break;
}
}
free(q->buffer);
}
free(q);
}
}
u8 *queue_buf_get_isr(struct queue_buf *q)
{
int next_tail = (q->tail + 1) % q->capacity;
// 如果 next_tail == head,则说明队列已满
if (next_tail == q->head) {
/* printf("F %d %d \n", q->head, q->tail); */
return NULL;
}
return q->buffer[q->tail];
}
void queue_buf_push_isr(struct queue_buf *q)
{
q->tail = (q->tail + 1) % q->capacity;
}
u8 *queue_buf_pop(struct queue_buf *q)
{
if (q->head == q->tail) {
return NULL;
}
return q->buffer[q->head];
}
void queue_buf_release(struct queue_buf *q)
{
q->head = (q->head + 1) % q->capacity;
}
void queue_buf_reset(struct queue_buf *q)
{
q->head = 0;
q->tail = 0;
}
@@ -0,0 +1,27 @@
#ifndef CAMERA_QUEUE_BUF_H
#define CAMERA_QUEUE_BUF_H
#include "system/includes.h"
struct queue_buf {
u8 **buffer;
int buf_size;
int capacity;
volatile int head;
volatile int tail;
int abort;
};
struct queue_buf *queue_buf_create(int buf_size, int capacity);
void queue_buf_destroy(struct queue_buf *q);
u8 *queue_buf_get_isr(struct queue_buf *q);
void queue_buf_push_isr(struct queue_buf *q);
u8 *queue_buf_pop(struct queue_buf *q);
void queue_buf_release(struct queue_buf *q);
void queue_buf_reset(struct queue_buf *q);
#endif /* CAMERA_QUEUE_BUF_H */
@@ -0,0 +1,265 @@
#include "system/includes.h"
#include "app_config.h"
// 如果定义了 USE_PSRAM,就把 malloc/free 映射到 malloc_psram/free_psram
#if TCFG_PSRAM_DEV_ENABLE
#define malloc(size) malloc_psram(size)
#define free(ptr) free_psram(ptr)
#else
#define malloc(size) malloc(size)
#define free(ptr) free(ptr)
#endif
extern int jpgenc_get_heapsize(int width, int height);
extern void *jpgenc_init(unsigned char *heap, int width, int height, int stride, int quality);
extern void jpgenc_free(void *ctxt);
extern void jpgenc_set_quality(void *ctxt, int quality);
extern void jpgenc_get_header(void *ctxt, unsigned char **output, int *out_size);
extern void jpgenc_encode_yuyv(void *ctxt, unsigned char *data, unsigned char *output, int *out_size, int vlen, int voff);
struct software_jpegenc_hdl {
void *jfif;
u8 *heap;
u8 *jpeg_header;
int jpeg_header_size;
};
/* ------------------------------------------------------------------------------------*/
/**
* @brief software_jpegenc_init jpeg软件分行编码初始化
*
* @param img_width 图像宽
* @param img_height 图像高
* @param img_stride
* @param q_val 编码Q值,范围(1-100)
* @return enc_hdl_ptr:成功 NULL:失败
*/
/* ------------------------------------------------------------------------------------*/
void *software_jpegenc_init(int img_width, int img_height, int img_stride, int q_val)
{
struct software_jpegenc_hdl *hdl = malloc(sizeof(struct software_jpegenc_hdl));
if (!hdl) {
printf("jpgenc hdl malloc fail \n");
return NULL;
}
memset(hdl, 0x00, sizeof(struct software_jpegenc_hdl));
//获取jpg头信息大小
int heapsize = jpgenc_get_heapsize(img_width, img_height);
/* printf("jpgenc heapsize:%d \n",heapsize); */
// 申请jpg头部控件
u8 *heap = malloc(heapsize);
if (!heap) {
printf("jpgenc heap malloc fail \n");
free(hdl);
return NULL;
}
//JPG图像编码初始化
u8 *header;
int header_size;
void *jfif = jpgenc_init(heap, img_width, img_height, img_stride, q_val);
jpgenc_get_header(jfif, &header, &header_size);
/* printf("jpgenc header_size:%d \n",header_size); */
hdl->jfif = jfif;
hdl->heap = heap;
hdl->jpeg_header = header;
hdl->jpeg_header_size = header_size;
return (void *)hdl;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief software_jpegenc_line jpeg软件分行编码
*
* @param jpgenc_hdl 编码句柄,software_jpegenc_init获取
* @param out_buf 编码位流保存buf
* @param out_buf_size 编码位流保存buf大小
* @param in_data 待编码的YUYV数据buf
* @param vlen 编码行数
* @param voff 编码行数偏移
* @param jpgenc_out_size 此次编码输出位流的大小
*
* @return 0:成功 -1:失败
*/
/* ------------------------------------------------------------------------------------*/
int software_jpegenc_line(void *jpgenc_hdl, u8 *out_buf, int out_buf_size, u8 *in_data, int vlen, int voff, int *jpgenc_out_size)
{
if (!jpgenc_hdl || !out_buf || !in_data) {
printf("jpgenc ptr err \n");
return -1;
}
struct software_jpegenc_hdl *hdl = (struct software_jpegenc_hdl *)jpgenc_hdl;
int total_size = 0;
u8 *buf_ptr = out_buf;
int buf_size = out_buf_size;
if (voff == 0) {
if (buf_size < hdl->jpeg_header_size) {
printf("jpgenc header buf_size err buf_size:%d need size:%d \n",
buf_size, hdl->jpeg_header_size);
return -1;
}
memcpy(out_buf, hdl->jpeg_header, hdl->jpeg_header_size);
buf_ptr += hdl->jpeg_header_size;
buf_size -= hdl->jpeg_header_size;
total_size += hdl->jpeg_header_size;
}
int out_size = buf_size;
jpgenc_encode_yuyv(hdl->jfif, in_data, buf_ptr, &out_size, vlen, voff);
if (out_size == buf_size) {
printf("jpgenc encode buf_size err \n");
return -1;
}
total_size += out_size;
*jpgenc_out_size = total_size;
return 0;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief software_jpegenc_exit jpeg软件编码退出流程,释放内存
*
* @param jpgenc_hdl init时申请的句柄
*
*/
/* ------------------------------------------------------------------------------------*/
void software_jpegenc_exit(void *jpgenc_hdl)
{
if (!jpgenc_hdl) {
return;
}
struct software_jpegenc_hdl *hdl = (struct software_jpegenc_hdl *)jpgenc_hdl;
if (hdl->heap) {
free(hdl->heap);
}
if (hdl->jfif) {
jpgenc_free(hdl->jfif);
}
free(hdl);
}
//测试代码
//os_task_create(software_jpegenc_demo_task,NULL,10,2048,1024,"jpegenc_demo_task");
void software_jpegenc_demo_task(void *priv)
{
mem_stats();
//1.128x128 YUYV
int img_width = 240; //图片宽
int img_height = 320; //图片高
int vlen = 32; //每次编码的行数
void *fp = NULL, *w_fp = NULL;
int jpeg_buf_size, yuv_buf_size, cur_enc_line, out_buf_size, jpgenc_out_total_size;
u8 *jpeg_buf = NULL, *yuv_buf = NULL, *out_buf = NULL;
void *enc_hdl = NULL;
uint32_t enc_time;
fp = (void *)fopen("storage/sd0/C/output1.yuy", "r");
if (!fp) {
printf("fopen err \n");
goto exit;
}
printf("yuv file len:%d \n", flen(fp));
//确保内存足够装下, 测试图片240*320 Q值50,编码出来8K内存
jpeg_buf_size = 20 * 1024;
jpeg_buf = malloc(jpeg_buf_size);
if (!jpeg_buf) {
printf("malloc jpg buf err \n");
mem_stats();
goto exit;
}
yuv_buf_size = img_width * vlen * 2;
yuv_buf = malloc(yuv_buf_size);
if (!yuv_buf) {
printf("malloc yuv buf err \n");
mem_stats();
goto exit;
}
enc_hdl = software_jpegenc_init(img_width, img_height, img_width, 50);
if (!enc_hdl) {
printf("software jpegenc init err \n");
goto exit;
}
cur_enc_line = 0;
out_buf = jpeg_buf;
out_buf_size = jpeg_buf_size;
jpgenc_out_total_size = 0;
enc_time = 0;
while (cur_enc_line < img_height) {
int jpgenc_out_size = 0;
if (fread(yuv_buf, 1, yuv_buf_size, fp) != yuv_buf_size) {
printf("yuv fread err \n");
goto exit;
}
uint32_t timer_get_ms(void);
uint32_t enc_start_time = timer_get_ms();
if (software_jpegenc_line(enc_hdl, out_buf, out_buf_size, yuv_buf, vlen, cur_enc_line, &jpgenc_out_size)) {
printf("software jpgenc line err \n");
goto exit;
}
enc_time += timer_get_ms() - enc_start_time;
out_buf += jpgenc_out_size;
out_buf_size -= jpgenc_out_size;
jpgenc_out_total_size += jpgenc_out_size;
cur_enc_line += vlen;
}
printf("jpgenc finish use time: %dms jpg size:%d \n", enc_time, jpgenc_out_total_size);
w_fp = fopen("storage/sd0/C/output1.jpg", "w+");
if (!w_fp) {
printf("jpeg fopen err \n");
goto exit;
}
if (fwrite(jpeg_buf, 1, jpgenc_out_total_size, w_fp) != jpgenc_out_total_size) {
printf("jpeg fwrite err \n");
goto exit;
}
exit:
printf("software_jpegenc_demo_task exit \n");
if (w_fp) {
fclose(w_fp);
w_fp = NULL;
}
if (fp) {
fclose(fp);
fp = NULL;
}
if (enc_hdl) {
software_jpegenc_exit(enc_hdl);
enc_hdl = NULL;
}
if (yuv_buf) {
free(yuv_buf);
yuv_buf = NULL;
}
if (jpeg_buf) {
free(jpeg_buf);
jpeg_buf = NULL;
}
mem_stats();
os_time_dly(-1);
}
@@ -0,0 +1,46 @@
#ifndef SOFTWARE_JPEGENC_H
#define SOFTWARE_JPEGENC_H
/* ------------------------------------------------------------------------------------*/
/**
* @brief software_jpegenc_init jpeg软件分行编码初始化
*
* @param img_width 图像宽
* @param img_height 图像高
* @param img_stride
* @param q_val 编码Q值,范围(1-100)
* @return enc_hdl_ptr:成功 NULL:失败
*/
/* ------------------------------------------------------------------------------------*/
void *software_jpegenc_init(int img_width, int img_height, int img_stride, int q_val);
/* ------------------------------------------------------------------------------------*/
/**
* @brief software_jpegenc_line jpeg软件分行编码
*
* @param jpgenc_hdl 编码句柄,software_jpegenc_init获取
* @param out_buf 编码位流保存buf
* @param out_buf_size 编码位流保存buf大小
* @param in_data 待编码的YUYV数据buf
* @param vlen 编码行数
* @param voff 编码行数偏移
* @param jpgenc_out_size 此次编码输出位流的大小
*
* @return 0:成功 -1:失败
*/
/* ------------------------------------------------------------------------------------*/
int software_jpegenc_line(void *jpgenc_hdl, u8 *out_buf, int out_buf_size, u8 *in_data, int vlen, int voff, int *jpgenc_out_size);
/* ------------------------------------------------------------------------------------*/
/**
* @brief software_jpegenc_exit jpeg软件编码退出流程,释放内存
*
* @param jpgenc_hdl init时申请的句柄
*
*/
/* ------------------------------------------------------------------------------------*/
void software_jpegenc_exit(void *jpgenc_hdl);
#endif /* SOFTWARE_JPEGENC_H */
+308
View File
@@ -0,0 +1,308 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".mic_data.data.bss")
#pragma data_seg(".mic_data.data")
#pragma const_seg(".mic_data.text.const")
#pragma code_seg(".mic_data.text")
#endif
/*****************************************************************
>file name : voice_mic_data.c
>author : lichao
>create time : Mon 01 Nov 2021 11:33:32 AM CST
*****************************************************************/
#include "app_config.h"
#include "app_main.h"
#include "adc_file.h"
#include "effects/convert_data.h"
#include "circular_buf.h"
#include "media/audio_general.h"
#include "audio_splicing.h"
#include "mic_data.h"
extern struct audio_adc_hdl adc_hdl;
#define MAIN_ADC_GAIN 8
#define MAIN_ADC_BUF_NUM 3
struct main_adc_context {
struct audio_adc_output_hdl dma_output;
struct adc_mic_ch mic_ch;
s16 *dma_buf;
s16 *mic_sample_data;;
u8 adc_ch_num; //打开的adc ch数量
u8 adc_seq; //记录当前用的那个mic
u8 bit_width;
};
/*
* Mic 数据接收buffer(循环buffer,动态大小)
*/
struct voice_mic_data {
u8 open;
u8 source;
struct main_adc_context *main_adc;
void *vad_mic;
struct list_head head;
cbuffer_t cbuf;
u8 buf[0];
};
struct voice_mic_capture_channel {
void *priv;
void (*output)(void *priv, s16 *data, int len);
struct list_head entry;
};
static struct voice_mic_data *voice_handle = NULL;
extern const u8 const_adc_async_en;
#define __this (voice_handle)
int mic_data_write(void *mic, void *data, int len);
static int voice_mic_data_output(void *priv, s16 *data, int len)
{
struct voice_mic_data *voice = (struct voice_mic_data *)priv;
int wlen = 0;
{
struct voice_mic_capture_channel *ch;
list_for_each_entry(ch, &voice->head, entry) {
if (ch->output) {
ch->output(ch->priv, data, len);
}
}
wlen = mic_data_write(priv, data, len);
}
return wlen;
}
static void audio_main_adc_dma_data_handler(void *priv, s16 *data, int len)
{
struct voice_mic_data *voice = (struct voice_mic_data *)priv;
if (!voice || voice->source != VOICE_MCU_MIC) {
return;
}
s16 *pcm_data = NULL;
if (voice->main_adc->bit_width != ADC_BIT_WIDTH_16) {
s32 *s32_src = (s32 *)data;
s32 *s32_dst = (s32 *)voice->main_adc->mic_sample_data;
if (voice->main_adc->adc_ch_num > 1) {
for (int i = 0; i < len / 4; i++) {
s32_dst[i] = s32_src[i * voice->main_adc->adc_ch_num + voice->main_adc->adc_seq];
}
audio_convert_data_32bit_to_16bit_round(s32_dst, (s16 *)s32_dst, len / 4);
} else {
audio_convert_data_32bit_to_16bit_round(s32_src, (s16 *)s32_dst, len / 4);
}
pcm_data = (s16 *)s32_dst;
len >>= 1;
} else {
s16 *s16_src = (s16 *)data;
s16 *s16_dst = (s16 *)voice->main_adc->mic_sample_data;
if (voice->main_adc->adc_ch_num > 1) {
for (int i = 0; i < len / 2; i++) {
s16_dst[i] = s16_src[i * voice->main_adc->adc_ch_num + voice->main_adc->adc_seq];
}
pcm_data = (s16 *)s16_dst;
} else {
pcm_data = (s16 *)data;
}
}
/* putchar('M'); */
voice_mic_data_output(voice, pcm_data, len);
}
static int audio_main_adc_mic_open(struct voice_mic_data *voice, int sample_rate)
{
int ret = 0;
if (voice->main_adc) {
printf("audio main adc mic already open !!!");
return 0;
}
voice->main_adc = zalloc(sizeof(struct main_adc_context));
if (!voice->main_adc) {
return -ENOMEM;
}
if (const_adc_async_en) {
/*是否4个adc通道都打开,音箱使用*/
voice->main_adc->adc_ch_num = 4;
} else {
/*默认打开一个adc通道做语音识别,耳机使用*/
voice->main_adc->adc_ch_num = 1;
}
voice->main_adc->bit_width = adc_hdl.bit_width;
/*设置adc buf大小*/
int dma_len = 0;
if (voice->main_adc->bit_width == ADC_BIT_WIDTH_16) {
dma_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short) * MAIN_ADC_BUF_NUM * voice->main_adc->adc_ch_num;
} else {
dma_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(int) * MAIN_ADC_BUF_NUM * voice->main_adc->adc_ch_num;
}
voice->main_adc->dma_buf = zalloc(dma_len);
printf("adc dma_len %d ", dma_len);
/*设置缓存buf大小*/
int buf_len = 0;
if (voice->main_adc->bit_width == ADC_BIT_WIDTH_16) {
if (voice->main_adc->adc_ch_num > 1) {
buf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short);
}
} else {
if (voice->main_adc->adc_ch_num > 1) {
buf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(int);
} else {
buf_len = VOICE_MIC_DATA_PERIOD_FRAMES * sizeof(short);
}
}
printf("mic sample data len %d", buf_len);
if (buf_len) {
voice->main_adc->mic_sample_data = zalloc(buf_len);
}
/*配置使用哪个mic做语音识别*/
#ifdef TCFG_SMART_VOICE_MIC_CH_SEL
u8 ch = TCFG_SMART_VOICE_MIC_CH_SEL;
#else
u8 ch = AUDIO_ADC_MIC_0;
#endif
printf("%s:%d", __func__, ch);
audio_adc_file_init();
if (ch & AUDIO_ADC_MIC_0) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_0);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_0, MAIN_ADC_GAIN);
}
if (ch & AUDIO_ADC_MIC_1) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_1);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_1, MAIN_ADC_GAIN);
}
if (ch & AUDIO_ADC_MIC_2) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_2);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_2, MAIN_ADC_GAIN);
}
if (ch & AUDIO_ADC_MIC_3) {
adc_file_mic_open(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_3);
audio_adc_mic_set_gain(&voice->main_adc->mic_ch, AUDIO_ADC_MIC_3, MAIN_ADC_GAIN);
}
audio_adc_mic_set_sample_rate(&voice->main_adc->mic_ch, sample_rate);
ret = audio_adc_mic_set_buffs(&voice->main_adc->mic_ch, voice->main_adc->dma_buf,
VOICE_MIC_DATA_PERIOD_FRAMES * 2, MAIN_ADC_BUF_NUM);
if (ret && voice->main_adc->dma_buf) {
/*已经设置过buf了,并不需要在set buf*/
free(voice->main_adc->dma_buf);
voice->main_adc->dma_buf = NULL;
}
voice->main_adc->dma_output.priv = voice;
voice->main_adc->dma_output.handler = audio_main_adc_dma_data_handler;
audio_adc_add_output_handler(&adc_hdl, &voice->main_adc->dma_output);
audio_adc_mic_start(&voice->main_adc->mic_ch);
voice->main_adc->adc_seq = get_adc_seq(&adc_hdl, ch); //查询模拟mic对应的ADC通道,打开4个adc通道时使用
printf("adc_seq %d", voice->main_adc->adc_seq);
return 0;
}
static void audio_main_adc_mic_close(struct voice_mic_data *voice, u8 all_channel)
{
if (voice && voice->main_adc) {
if (all_channel) {
audio_adc_mic_close(&voice->main_adc->mic_ch);
}
audio_adc_del_output_handler(&adc_hdl, &voice->main_adc->dma_output);
if (voice->main_adc->dma_buf) {
/*mic close时会自动释放内存?*/
/* free(voice->main_adc->dma_buf); */
voice->main_adc->dma_buf = NULL;
}
if (voice->main_adc->mic_sample_data) {
free(voice->main_adc->mic_sample_data);
voice->main_adc->mic_sample_data = NULL;
}
free(voice->main_adc);
voice->main_adc = NULL;
}
}
void *mic_data_open(u8 source, int buffer_size, int sample_rate)
{
if (__this && __this->open) {
return __this;
}
void *mic_data_cbuf_init(int buffer_size);
__this = mic_data_cbuf_init(buffer_size);
__this->source = source;
INIT_LIST_HEAD(&__this->head);
audio_main_adc_mic_open(__this, sample_rate);
__this->open = 1;
return __this;
}
void mic_data_close(void *mic)
{
struct voice_mic_data *voice = (struct voice_mic_data *)mic;
if (voice) {
audio_main_adc_mic_close(voice, 1);
free(voice);
}
/* int mic_data_cbuf_deinit(void *mc); */
/* mic_data_cbuf_deinit(__this); */
__this = NULL;
}
void *mic_data_cbuf_init(int buffer_size)
{
if (!__this) {
__this = zalloc(sizeof(struct voice_mic_data) + buffer_size);
}
cbuf_init(&__this->cbuf, __this->buf, buffer_size);
return __this;
}
int mic_data_cbuf_deinit(void *mic)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
if (fb) {
free(fb);
}
return 0;
}
int mic_data_write(void *mic, void *data, int len)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
int wlen = 0;
wlen = cbuf_write(&fb->cbuf, data, len);
if (wlen < len) {
putchar('D');
}
return wlen;
}
int mic_data_read(void *mic, void *data, int len)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
/* printf("%s. %d, %d", __func__, len, cbuf_get_data_len(&fb->cbuf)); */
if (cbuf_get_data_len(&fb->cbuf) < len) {
return 0;
} else {
int wlen = cbuf_read(&fb->cbuf, data, len);
return wlen;
}
}
int mic_data_buffered_samples(void *mic)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
return cbuf_get_data_len(&fb->cbuf) >> 1;
}
void mic_data_clear(void *mic)
{
struct voice_mic_data *fb = (struct voice_mic_data *)mic;
cbuf_clear(&fb->cbuf);
}
+23
View File
@@ -0,0 +1,23 @@
#ifndef MIC_DATA_H
#define MIC_DATA_H
#include "asm/audio_adc.h"
#define VOICE_VAD_MIC 0
#define VOICE_MCU_MIC 1
#define VOICE_DEFULT_MIC VOICE_VAD_MIC
#define VOICE_ADC_SAMPLE_RATE 16000
#define VOICE_ADC_SAMPLE_CH 1
#define VOICE_MIC_DATA_SAMPLE_PREIOD 10
#define VOICE_MIC_DATA_PERIOD_FRAMES (VOICE_MIC_DATA_SAMPLE_PREIOD * VOICE_ADC_SAMPLE_RATE / 1000)
void *mic_data_open(u8 source, int buffer_size, int sample_rate);
void mic_data_close(void *mic);
int mic_data_read(void *mic, void *data, int len);
int mic_data_buffered_samples(void *mic);
void mic_data_clear(void *mic);
#endif /* MIC_DATA_H */
+281
View File
@@ -0,0 +1,281 @@
#include "system/includes.h"
#include "app_config.h"
#include "mic_data.h"
#include "lbuf.h"
// 如果定义了 USE_PSRAM,就把 malloc/free 映射到 malloc_psram/free_psram
#if TCFG_PSRAM_DEV_ENABLE
#define malloc(size) malloc_psram(size)
#define free(ptr) free_psram(ptr)
#else
#define malloc(size) malloc(size)
#define free(ptr) free(ptr)
#endif
#define offsetof(type, memb) \
((unsigned long)(&((type *)0)->memb))
enum {
Q_PCM_TASK_KILL = (Q_USER + 100),
};
#define USED_JL_STREAM_ENABLE 0
#define MIC_BUFFER_SIZE 4 * 1024
#define MIC_READ_LEN 512
struct lbuf_data_head {
int len;
u8 data[0];
};
struct pcm_data_hdl {
void *mic;
int frame_size;
int sample_rate;
u8 *lbuf_ptr;
struct lbuff_head *lbuf_handle;
OS_SEM task_kill_sem;
char task_name[32];
};
static void pcm_data_task(void *priv)
{
printf("pcm data task run !\n");
struct pcm_data_hdl *hdl = (struct pcm_data_hdl *)priv;
struct lbuf_data_head *lbuf_data = NULL;
int read_szie = 0;
int msg[8];
while (1) {
if (os_taskq_accept(ARRAY_SIZE(msg), msg) == OS_TASKQ) {
if (msg[0] == Q_PCM_TASK_KILL) {
printf("pcm data task exit !\n");
os_sem_post((OS_SEM *)msg[1]);
os_time_dly(-1);
}
}
if (read_szie == 0 && !lbuf_data) {
lbuf_data = lbuf_alloc(hdl->lbuf_handle, hdl->frame_size);
if (!lbuf_data) {
printf("pcm data lbuf_alloc err \n");
os_time_dly(1);
continue;
}
} else if (read_szie == hdl->frame_size) {
lbuf_data->len = hdl->frame_size;
lbuf_push(lbuf_data, BIT(0));
lbuf_data = NULL;
read_szie = 0;
continue;
}
int remain_size = hdl->frame_size - read_szie;
int rlen = remain_size < MIC_READ_LEN ? remain_size : MIC_READ_LEN;
u8 *outbuf = lbuf_data->data + read_szie;
#if USED_JL_STREAM_ENABLE
int mic_data_cbuf_read(void *buf, int len);
int len = mic_data_cbuf_read(outbuf, rlen);
#else
int len = mic_data_read(hdl->mic, outbuf, rlen);
#endif
if (!len) {
uint32_t delay_ms = ((float)MIC_READ_LEN / (hdl->sample_rate * 2)) * 1000; //默认16位深
uint32_t tick = delay_ms / 10;
os_time_dly(tick + 1);
/* putchar('\n'); */
/* putchar('C'); */
} else {
read_szie += len;
/* printf("read_szie:%d len:%d \n", read_szie, len); */
}
}
}
void *pcm_data_init(int sample_rate, int frame_size, int buf_size)
{
struct pcm_data_hdl *hdl = malloc(sizeof(struct pcm_data_hdl));
if (!hdl) {
printf("pcm data hdl malloc fail \n");
goto err;
}
memset(hdl, 0x00, sizeof(struct pcm_data_hdl));
hdl->sample_rate = sample_rate;
hdl->frame_size = frame_size;
hdl->lbuf_ptr = malloc(buf_size);
if (!hdl->lbuf_ptr) {
printf("pcm data lbuf_ptr malloc fail \n");
goto err;
}
hdl->lbuf_handle = lbuf_init(hdl->lbuf_ptr, buf_size, 4, sizeof(struct lbuf_data_head));
#if USED_JL_STREAM_ENABLE
hdl->mic = NULL;
//开音频流
int avi_video_recoder_open();
if (avi_video_recoder_open()) {
printf("%s avi_video_recoder err\n", __func__);
goto err;
}
#else
hdl->mic = mic_data_open(VOICE_MCU_MIC, MIC_BUFFER_SIZE, sample_rate);
if (!hdl->mic) {
printf("mic data open err \n");
goto err;
}
#endif
snprintf(hdl->task_name, sizeof(hdl->task_name), "pcm_data_task");
os_sem_create(&hdl->task_kill_sem, 0);
if (os_task_create(pcm_data_task, hdl, 10, 1024, 1024, hdl->task_name)) {
printf("pcm data task create fail \n");
goto err;
}
return (void *)hdl;
err:
if (hdl) {
if (hdl->mic) {
mic_data_close(hdl->mic);
}
#if USED_JL_STREAM_ENABLE
void avi_video_recoder_close();
avi_video_recoder_close();
#endif
if (hdl->lbuf_ptr) {
free(hdl->lbuf_ptr);
}
free(hdl);
}
return NULL;
}
void pcm_data_exit(void *data_hdl)
{
if (!data_hdl) {
return;
}
struct pcm_data_hdl *hdl = (struct pcm_data_hdl *)data_hdl;
int msg = (int)&hdl->task_kill_sem;
os_taskq_post_type(hdl->task_name, Q_PCM_TASK_KILL, 1, &msg);
os_sem_pend(&hdl->task_kill_sem, 0);
os_sem_del(&hdl->task_kill_sem, OS_DEL_ALWAYS);
task_kill(hdl->task_name);
if (hdl->mic) {
mic_data_close(hdl->mic);
}
#if USED_JL_STREAM_ENABLE
void avi_video_recoder_close();
avi_video_recoder_close();
#endif
if (hdl->lbuf_ptr) {
free(hdl->lbuf_ptr);
}
free(hdl);
}
int pcm_data_read(void *data_hdl, u8 **pp_data, int *p_len)
{
struct lbuf_data_head *node;
if (!data_hdl || !pp_data || !p_len) {
printf("pcm data read ptr err \n");
return -1;
}
struct pcm_data_hdl *hdl = (struct pcm_data_hdl *)data_hdl;
node = lbuf_pop(hdl->lbuf_handle, BIT(0));
if (!node) {
return -2;
}
*pp_data = node->data;
*p_len = node->len;
return 0;
}
int pcm_data_read_done(void *data_hdl, u8 *data_buf)
{
struct lbuf_data_head *node;
if (!data_hdl || !data_buf) {
printf("pcm data read done ptr err \n");
return -1;
}
struct pcm_data_hdl *hdl = (struct pcm_data_hdl *)data_hdl;
/* offsetof(struct lbuf_data_head, data) 就是 data 字段相对于结构体开头的字节偏移 */
node = (struct lbuf_data_head *)((u8 *)data_buf - offsetof(struct lbuf_data_head, data));
lbuf_free(node);
return 0;
}
// demo
// os_task_create(pcm_data_demo,NULL,10,2048,1024,"pcm_data_demo");
void pcm_data_demo(void *priv)
{
printf("pcm data dem run !\n");
int frame_size = 4096;
int sample_rate = 8000;
void *hdl = pcm_data_init(sample_rate, frame_size, frame_size * 10);
u8 *pcm;
int len;
void *fp = (void *)fopen("storage/sd0/C/output.pcm", "w+");
if (!fp) {
printf("pcm data demo fopen err \n");
goto exit;
}
int frame_cnt = 4 * 100;
while (1) {
if (!frame_cnt) {
printf("pcm data demo read done \n");
break;
}
if (pcm_data_read(hdl, &pcm, &len) == 0) {
if (fwrite(pcm, 1, len, fp) != len) {
printf("pcm data demo fwrite err \n");
}
pcm_data_read_done(hdl, pcm);
frame_cnt--;
} else {
/* putchar('D'); */
uint32_t delay_ms = ((float)frame_size / (sample_rate * 2)) * 1000;
uint32_t tick = delay_ms / 10;
os_time_dly(tick + 1);
}
}
fclose(fp);
exit:
if (hdl) {
pcm_data_exit(hdl);
}
os_time_dly(-1);
}
+11
View File
@@ -0,0 +1,11 @@
#ifndef PCM_DATA_H
#define PCM_DATA_H
void *pcm_data_init(int sample_rate, int frame_size, int buf_size);
void pcm_data_exit(void *data_hdl);
int pcm_data_read(void *data_hdl, u8 **pp_data, int *p_len);
int pcm_data_read_done(void *data_hdl, u8 *data_buf);
#endif /* PCM_DATA_H */
+65
View File
@@ -0,0 +1,65 @@
#include "avilib.h"
//读取AVI文件视频帧和音频帧行写卡在PC上验证
int video_dec_demo(void)
{
char *filename = "storage/sd0/C/VID_0001.AVI";
avi_t *in_fd = AVI_open_input_file(filename, 1);
if (in_fd == NULL) {
printf("AVI_open_input_file err \n");
return -1;
}
u8 *file_buf = malloc(20 * 1024);
if (!file_buf) {
printf("file_buf malloc err\n");
return -1;
}
int total_frame = AVI_video_frames(in_fd);
printf("AVI total video frame:%d \n", total_frame);
int audio_chunks = AVI_audio_chunks(in_fd);
printf("AVI total audio frame:%d \n", audio_chunks);
char save_file_name[64];
int i = 0;
for (i = 0; i < total_frame; i++) {
AVI_set_video_position(in_fd, i);
int keyframe;
int file_len = AVI_read_frame(in_fd, (char *)file_buf, &keyframe);
if (file_len > 0) {
printf("write video frame:%d \n", i);
snprintf(save_file_name, sizeof(save_file_name), "storage/sd0/C/avi_test/jpg_%d.jpg", i);
FILE *fd = fopen(save_file_name, "w+");
fwrite(file_buf, 1, file_len, fd);
fclose(fd);
}
}
snprintf(save_file_name, sizeof(save_file_name), "storage/sd0/C/avi_test/test.pcm");
FILE *fd = fopen(save_file_name, "w+");
u32 offset = 0;
for (i = 0; i < audio_chunks; i++) {
int audio_chunk_size = AVI_audio_size(in_fd, i);
AVI_set_audio_position(in_fd, offset);
int file_len = AVI_read_audio_chunk(in_fd, (char *)file_buf);
if (file_len > 0) {
printf("write audio frame:%d size:%d chunk_size:%d \n", i, file_len, audio_chunk_size);
fwrite(file_buf, 1, file_len, fd);
}
offset += audio_chunk_size;
}
fclose(fd);
AVI_close(in_fd);
free(file_buf);
/* os_time_dly(-1); */
return 0;
}
+501
View File
@@ -0,0 +1,501 @@
#include "app_config.h"
#include "video_rec.h"
#include "bf30a2_cfg.h"
#include "camera_manager.h"
#include "avilib.h"
#include "pcm_data.h"
#include "clock_manager/clock_manager.h"
#define LOG_TAG_CONST VIDEO_REC
#define LOG_TAG "[VIDEO_REC]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_CHAR_ENABLE //log_char enable */
#define LOG_CLI_ENABLE
#include "debug.h"
#if TCFG_CAMERA_MANAGER_ENABLE
enum {
Q_AVI_TASK_KILL = (Q_USER + 100),
Q_AVI_TASK_REC_START,
Q_AVI_TASK_REC_STOP,
};
struct video_rec_handle {
void *pcm_hdl;
char avi_task_name[32];
u8 write_error; //写文件异常
u8 busy;
int aframe_size;
int video_rate;
int sample_rate;
void (*ui_refresh_cb)(int status);
};
static struct video_rec_handle *video_rec;
#define __this (video_rec)
//摄像头流程 camera_manager_init->start->read->read_done->read...->stop->exit.
//麦克风流程 pcm_data_init->read->read_done->read...->exit.
extern int jljpeg_stream_src_data_copy(u8 *buf, int size);
extern void camera_dec_flush(void);
static void jlcamera_ui_reflush(void)
{
if (__this && __this->ui_refresh_cb) {
__this->ui_refresh_cb(__this->write_error);
}
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_refresh_cb 注册刷新回调
*
* @param cb ui 刷新回调
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_refresh_cb(void (*cb)(int status))
{
if (!__this) {
log_error("%s not find\n", __func__);
return -1;
}
__this->ui_refresh_cb = cb;
return 0;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_start 启动录像
*
* @param filename 录制文件路径
* @param cyc_time 循环录制(-1不循环)
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_start(char *filename, int cyc_time)
{
log_debug("%s file_name:%s cyc_time:%d\n", __func__, filename, cyc_time);
if (!__this) {
log_error("%s not init\n", __func__);
return -1;
}
int msg[3] = {0};
msg[0] = (u32)filename;
msg[1] = cyc_time;
return os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_REC_START, 2, msg);
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_stop 暂停录制
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_stop()
{
if (!__this) {
log_error("%s not init\n", __func__);
return -1;
}
log_debug("%s \n", __func__);
return os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_REC_STOP, 0, NULL);
}
static void video_show_task(void *priv)
{
log_debug("%s enter>>>>>>>>>>>>>>>>>>>>\n ", __func__);
int ret = 0;
int msg[8];
int frame_cnt = 0;
int frame_width = 0;
int frame_height = 0;
int cyc_time = -1; //循环录影时间,单位秒,-1不循环
u8 *pcm_data, *jpeg_data;
int pcm_data_len, jpeg_data_len;
char *filename = NULL;
avi_t *out_fd = NULL;
camera_manager_get_dev_width_height(&frame_width, &frame_height);
log_info("%s frame[%d x %d] \n", __func__, frame_width, frame_height);
while (1) {
u8 read_data = 0;
if (os_taskq_accept(ARRAY_SIZE(msg), msg) == OS_TASKQ) {
if (msg[0] == Q_AVI_TASK_KILL) {
log_debug("avi task exit !\n");
if (out_fd) {
ret = AVI_close(out_fd);
if (ret) {
log_error("camera devide avi close err :%d \n", ret);
ASSERT(0);
} else {
log_debug("avi write success \n");
out_fd = NULL;
}
}
if (__this->pcm_hdl) {
pcm_data_exit(__this->pcm_hdl);
__this->pcm_hdl = NULL;
}
log_debug("%s exit >>>>>>>>>>>>>>>>>>>>\n ", __func__);
//下面禁止加打印{
os_sem_post((OS_SEM *)msg[1]);
os_time_dly(-1);
//}
break;
} else if (msg[0] == Q_AVI_TASK_REC_START) {
filename = (char *)msg[1];
cyc_time = msg[2];
__this->write_error = 0;
log_debug("avi task rec start <%s> cyc_time:%d !\n", filename, cyc_time);
__this->pcm_hdl = pcm_data_init(__this->sample_rate, __this->aframe_size, __this->aframe_size * 10);
if (!__this->pcm_hdl) {
//TODO
log_error("avi task rec start pcm err!!!\n");
/* break; */
__this->write_error = -1;
continue;
}
out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
log_error("open file erro\n");
__this->write_error = -1;
continue;
/* break; */
}
AVI_set_video_suggestbuffersize(out_fd, 20 * 1024); //建议缓存区20k,解码用
AVI_set_video(out_fd, frame_width, frame_height, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
frame_cnt = 0;
/* break; */
} else if (msg[0] == Q_AVI_TASK_REC_STOP) {
log_debug("avi task rec stop!\n");
if (out_fd) {
ret = AVI_close(out_fd);
if (ret) {
log_error("camera devide avi close err :%d \n", ret);
ASSERT(0);
} else {
log_debug("avi write success \n");
out_fd = NULL;
}
}
if (__this->pcm_hdl) {
pcm_data_exit(__this->pcm_hdl);
__this->pcm_hdl = NULL;
}
__this->write_error = 0;
/* break; */
}
}
log_char('\n');
log_char('C');
//录像输出
if (out_fd) {
if (pcm_data_read(__this->pcm_hdl, &pcm_data, &pcm_data_len) == 0) {
read_data = 1;
__this->write_error = AVI_write_audio(out_fd, (char *)pcm_data, pcm_data_len);
pcm_data_read_done(__this->pcm_hdl, pcm_data);
}
}
if (camera_manager_data_read(&jpeg_data, &jpeg_data_len) == 0) {
log_char('M');
read_data = 1;
frame_cnt ++;
#if ((defined TCFG_UI_ENABLE) && TCFG_UI_ENABLE)
//ui帧输出
if (!jljpeg_stream_src_data_copy(jpeg_data, jpeg_data_len)) {
log_char('R');
jlcamera_ui_reflush();
}
#endif
if (out_fd) { //录像输出
__this->write_error = AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
}
camera_manager_read_done(jpeg_data);
}
if (out_fd && (cyc_time != -1)) {
if (frame_cnt == __this->video_rate * cyc_time) {
ret = AVI_close(out_fd);
if (ret) {
log_error("camera avi close err :%d \n", ret);
} else {
log_debug("avi write success \n");
}
out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
log_error("open file erro\n");
continue;
}
AVI_set_video_suggestbuffersize(out_fd, 20 * 1024); //建议缓存区20k,解码用
AVI_set_video(out_fd, frame_width, frame_height, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
frame_cnt = 0;
}
}
//没有读到数据
if (!read_data) {
//根据音频包计算延时
u32 delay_ms = ((float)__this->aframe_size / (__this->sample_rate * 2)) * 1000;
u32 tick = delay_ms / 10;
os_time_dly(tick + 1);
}
}
log_debug("%s exit >>>>>>>>>>>>>>>>>>>>\n ", __func__);
}
s8 *jlcamera_video_get_task_name()
{
if (__this) {
return __this->avi_task_name;
}
return NULL;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_init 初始化摄像头
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_init(void)
{
int ret = 0;
ASSERT(!__this);
__this = zalloc(sizeof(struct video_rec_handle));
__this->busy = 1;
clock_lock("camera_video", clk_get_max_frequency());
//初始化驱动
ret = camera_manager_init();
if (ret) {
//TODO
return -1;
}
//启动摄像头
ret = camera_manager_start();
if (ret) {
//TODO
return -1;
}
int fps;
camera_manager_get_dev_fps(&fps);
//视频帧率
__this->video_rate = fps / 2;
//音频采样率
__this->sample_rate = 8000;
__this->aframe_size = 4096;
snprintf(__this->avi_task_name, sizeof(__this->avi_task_name), "video_show_task");
if (os_task_create(video_show_task, __this, 8, 1024, 1024, __this->avi_task_name)) {
log_error("avi task create fail \n");
//TODO
return -1;
}
return 0;
}
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_deinit
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_deinit(void)
{
printf("%s %d", __func__, __LINE__);
/* void dma_memcpy_wait_idle(void); */
/* dma_memcpy_wait_idle(); */
camera_manager_stop();
OS_SEM task_kill_sem;
os_sem_create(&task_kill_sem, 0);
int msg = (int)&task_kill_sem;
os_taskq_del_type(__this->avi_task_name, Q_AVI_TASK_REC_START);
os_taskq_del_type(__this->avi_task_name, Q_AVI_TASK_REC_STOP);
os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_KILL, 1, &msg);
os_sem_pend(&task_kill_sem, 0);
os_sem_del(&task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->avi_task_name);
camera_manager_deinit();
clock_unlock("camera_video");
__this->busy = 0;
free(__this);
__this = NULL;
return 0;
}
static u8 jl_camera_video_idle_query(void)
{
if (__this) {
return __this->busy;
}
return 1;
}
REGISTER_LP_TARGET(camera_video_lp_target) = {
.name = "camera_video",
.is_idle = jl_camera_video_idle_query,
};
#endif
#if 0
//原代码
static void avi_task(void *priv)
{
int ret = 0;
int msg[8];
int frame_cnt = 0;
int cyc_time = 30; //循环录影时间,单位秒
u8 *pcm_data, *jpeg_data;
int pcm_data_len, jpeg_data_len;
char *filename = "storage/sd0/C/VID_****.AVI";
avi_t *out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
printf("open file erro\n");
os_time_dly(-1);
}
AVI_set_video(out_fd, BF30A2_INPUT_W, BF30A2_INPUT_H, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
while (1) {
u8 read_data = 0;
if (os_taskq_accept(ARRAY_SIZE(msg), msg) == OS_TASKQ) {
if (msg[0] == Q_AVI_TASK_KILL) {
if (out_fd) {
AVI_close(out_fd);
}
printf("avi task exit !\n");
os_sem_post((OS_SEM *)msg[1]);
os_time_dly(-1);
break;
}
}
if (pcm_data_read(__this->pcm_hdl, &pcm_data, &pcm_data_len) == 0) {
read_data = 1;
AVI_write_audio(out_fd, (char *)pcm_data, pcm_data_len);
pcm_data_read_done(__this->pcm_hdl, pcm_data);
}
if (bf30a2_camera_data_read(&jpeg_data, &jpeg_data_len) == 0) {
read_data = 1;
frame_cnt ++;
AVI_write_frame(out_fd, (char *)jpeg_data, jpeg_data_len, 1);
bf30a2_camera_read_done(jpeg_data);
}
if (frame_cnt == __this->video_rate * cyc_time) {
ret = AVI_close(out_fd);
if (ret) {
printf("bf30a2 avi close err :%d \n", ret);
} else {
printf("avi write success \n");
}
out_fd = AVI_open_output_file(filename);
if (out_fd == NULL) {
printf("open file erro\n");
break;
}
AVI_set_video(out_fd, BF30A2_INPUT_W, BF30A2_INPUT_H, __this->video_rate, "MJPG");
AVI_set_audio(out_fd, 1, __this->sample_rate, 16, WAVE_FORMAT_PCM, 0);//默认单声道s16格式
frame_cnt = 0;
}
//没有读到数据
if (!read_data) {
//根据音频包计算延时
u32 delay_ms = ((float)__this->aframe_size / (__this->sample_rate * 2)) * 1000;
u32 tick = delay_ms / 10;
os_time_dly(tick + 1);
}
}
}
int video_rec_start_demo(void)
{
int ret = 0;
ret = bf30a2_camera_init();
if (ret) {
//TODO
return -1;
}
ret = bf30a2_camera_start();
if (ret) {
//TODO
return -1;
}
__this->video_rate = BF30A2_INPUT_FPS / 2; //视频帧率
__this->sample_rate = 8000; //音频采样率
__this->aframe_size = 4096;
__this->pcm_hdl = pcm_data_init(__this->sample_rate, __this->aframe_size, __this->aframe_size * 10);
if (!__this->pcm_hdl) {
//TODO
return -1;
}
snprintf(__this->avi_task_name, sizeof(__this->avi_task_name), "avi_task");
if (os_task_create(avi_task, __this, 8, 1024, 1024, __this->avi_task_name)) {
printf("avi task create fail \n");
//TODO
return -1;
}
return 0;
}
int video_rec_stop_demo(void)
{
OS_SEM task_kill_sem;
os_sem_create(&task_kill_sem, 0);
int msg = (int)&task_kill_sem;
os_taskq_post_type(__this->avi_task_name, Q_AVI_TASK_KILL, 1, &msg);
os_sem_pend(&task_kill_sem, 0);
os_sem_del(&task_kill_sem, OS_DEL_ALWAYS);
task_kill(__this->avi_task_name);
pcm_data_exit(__this->pcm_hdl);
bf30a2_camera_stop();
bf30a2_camera_exit();
return 0;
}
#endif
+59
View File
@@ -0,0 +1,59 @@
#ifndef __VIDEO_REC__
#define __VIDEO_REC__
#include "app_config.h"
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_start 启动录像
*
* @param filename 录制文件路径
* @param cyc_time 循环录制(-1不循环)
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_start(char *filename, int cyc_time);
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_stop 暂停录制
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_stop();
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_init 初始化摄像头
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_init(void);
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_deinit
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_deinit(void);
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_rec_refresh_cb 注册刷新回调
*
* @param cb ui 刷新回调
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
int jlcamera_video_rec_refresh_cb(void (*cb)(int status));
/* ------------------------------------------------------------------------------------*/
/**
* @brief jlcamera_video_get_task_name 获取线程名
*
* @return
*/
/* ------------------------------------------------------------------------------------*/
s8 *jlcamera_video_get_task_name();
#endif //__VIDEO_REC__