初版
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -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
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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__
|
||||
Reference in New Issue
Block a user