📄 saa6752hs.c
字号:
#include <linux/module.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/string.h>#include <linux/timer.h>#include <linux/delay.h>#include <linux/errno.h>#include <linux/slab.h>#include <linux/poll.h>#include <linux/i2c.h>#include <linux/types.h>#include <linux/videodev.h>#include <linux/init.h>#include <linux/crc32.h>#include <media/id.h>#define MPEG_VIDEO_TARGET_BITRATE_MAX 27000#define MPEG_VIDEO_MAX_BITRATE_MAX 27000#define MPEG_TOTAL_TARGET_BITRATE_MAX 27000#define MPEG_PID_MAX ((1 << 14) - 1)/* Addresses to scan */static unsigned short normal_i2c[] = {0x20, I2C_CLIENT_END};I2C_CLIENT_INSMOD;MODULE_DESCRIPTION("device driver for saa6752hs MPEG2 encoder");MODULE_AUTHOR("Andrew de Quincey");MODULE_LICENSE("GPL");static struct i2c_driver driver;static struct i2c_client client_template;enum saa6752hs_videoformat { SAA6752HS_VF_D1 = 0, /* standard D1 video format: 720x576 */ SAA6752HS_VF_2_3_D1 = 1,/* 2/3D1 video format: 480x576 */ SAA6752HS_VF_1_2_D1 = 2,/* 1/2D1 video format: 352x576 */ SAA6752HS_VF_SIF = 3, /* SIF video format: 352x288 */ SAA6752HS_VF_UNKNOWN,};static const struct v4l2_format v4l2_format_table[] ={ [SAA6752HS_VF_D1] = { .fmt = { .pix = { .width = 720, .height = 576 }}}, [SAA6752HS_VF_2_3_D1] = { .fmt = { .pix = { .width = 480, .height = 576 }}}, [SAA6752HS_VF_1_2_D1] = { .fmt = { .pix = { .width = 352, .height = 576 }}}, [SAA6752HS_VF_SIF] = { .fmt = { .pix = { .width = 352, .height = 288 }}}, [SAA6752HS_VF_UNKNOWN] = { .fmt = { .pix = { .width = 0, .height = 0}}},};struct saa6752hs_state { struct i2c_client client; struct v4l2_mpeg_compression params; enum saa6752hs_videoformat video_format;};enum saa6752hs_command { SAA6752HS_COMMAND_RESET = 0, SAA6752HS_COMMAND_STOP = 1, SAA6752HS_COMMAND_START = 2, SAA6752HS_COMMAND_PAUSE = 3, SAA6752HS_COMMAND_RECONFIGURE = 4, SAA6752HS_COMMAND_SLEEP = 5, SAA6752HS_COMMAND_RECONFIGURE_FORCE = 6, SAA6752HS_COMMAND_MAX};/* ---------------------------------------------------------------------- */static u8 PAT[] = { 0xc2, // i2c register 0x00, // table number for encoder 0x47, // sync 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0) 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) 0x00, // PSI pointer to start of table 0x00, // tid(0) 0xb0, 0x0d, // section_syntax_indicator(1), section_length(13) 0x00, 0x01, // transport_stream_id(1) 0xc1, // version_number(0), current_next_indicator(1) 0x00, 0x00, // section_number(0), last_section_number(0) 0x00, 0x01, // program_number(1) 0xe0, 0x00, // PMT PID 0x00, 0x00, 0x00, 0x00 // CRC32};static u8 PMT[] = { 0xc2, // i2c register 0x01, // table number for encoder 0x47, // sync 0x40, 0x00, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid 0x10, // transport_scrambling_control(00), adaptation_field_control(01), continuity_counter(0) 0x00, // PSI pointer to start of table 0x02, // tid(2) 0xb0, 0x17, // section_syntax_indicator(1), section_length(23) 0x00, 0x01, // program_number(1) 0xc1, // version_number(0), current_next_indicator(1) 0x00, 0x00, // section_number(0), last_section_number(0) 0xe0, 0x00, // PCR_PID 0xf0, 0x00, // program_info_length(0) 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid 0x00, 0x00, 0x00, 0x00 // CRC32};static struct v4l2_mpeg_compression param_defaults ={ .st_type = V4L2_MPEG_TS_2, .st_bitrate = { .mode = V4L2_BITRATE_CBR, .target = 7000, }, .ts_pid_pmt = 16, .ts_pid_video = 260, .ts_pid_audio = 256, .ts_pid_pcr = 259, .vi_type = V4L2_MPEG_VI_2, .vi_aspect_ratio = V4L2_MPEG_ASPECT_4_3, .vi_bitrate = { .mode = V4L2_BITRATE_VBR, .target = 4000, .max = 6000, }, .au_type = V4L2_MPEG_AU_2_II, .au_bitrate = { .mode = V4L2_BITRATE_CBR, .target = 256, },};/* ---------------------------------------------------------------------- */static int saa6752hs_chip_command(struct i2c_client* client, enum saa6752hs_command command){ unsigned char buf[3]; unsigned long timeout; int status = 0; // execute the command switch(command) { case SAA6752HS_COMMAND_RESET: buf[0] = 0x00; break; case SAA6752HS_COMMAND_STOP: buf[0] = 0x03; break; case SAA6752HS_COMMAND_START: buf[0] = 0x02; break; case SAA6752HS_COMMAND_PAUSE: buf[0] = 0x04; break; case SAA6752HS_COMMAND_RECONFIGURE: buf[0] = 0x05; break; case SAA6752HS_COMMAND_SLEEP: buf[0] = 0x06; break; case SAA6752HS_COMMAND_RECONFIGURE_FORCE: buf[0] = 0x07; break; default: return -EINVAL; } // set it and wait for it to be so i2c_master_send(client, buf, 1); timeout = jiffies + HZ * 3; for (;;) { // get the current status buf[0] = 0x10; i2c_master_send(client, buf, 1); i2c_master_recv(client, buf, 1); if (!(buf[0] & 0x20)) break; if (time_after(jiffies,timeout)) { status = -ETIMEDOUT; break; } // wait a bit msleep(10); } // delay a bit to let encoder settle msleep(50); // done return status;}static int saa6752hs_set_bitrate(struct i2c_client* client, struct v4l2_mpeg_compression* params){ u8 buf[3]; // set the bitrate mode buf[0] = 0x71; buf[1] = (params->vi_bitrate.mode == V4L2_BITRATE_VBR) ? 0 : 1; i2c_master_send(client, buf, 2); // set the video bitrate if (params->vi_bitrate.mode == V4L2_BITRATE_VBR) { // set the target bitrate buf[0] = 0x80; buf[1] = params->vi_bitrate.target >> 8; buf[2] = params->vi_bitrate.target & 0xff; i2c_master_send(client, buf, 3); // set the max bitrate buf[0] = 0x81; buf[1] = params->vi_bitrate.max >> 8; buf[2] = params->vi_bitrate.max & 0xff; i2c_master_send(client, buf, 3); } else { // set the target bitrate (no max bitrate for CBR) buf[0] = 0x81; buf[1] = params->vi_bitrate.target >> 8; buf[2] = params->vi_bitrate.target & 0xff; i2c_master_send(client, buf, 3); } // set the audio bitrate buf[0] = 0x94; buf[1] = (256 == params->au_bitrate.target) ? 0 : 1; i2c_master_send(client, buf, 2); // set the total bitrate buf[0] = 0xb1; buf[1] = params->st_bitrate.target >> 8; buf[2] = params->st_bitrate.target & 0xff; i2c_master_send(client, buf, 3); // return success return 0;}static void saa6752hs_set_subsampling(struct i2c_client* client, struct v4l2_format* f){ struct saa6752hs_state *h = i2c_get_clientdata(client); int dist_352, dist_480, dist_720; /* FIXME: translate and round width/height into EMPRESS subsample type: type | PAL | NTSC --------------------------- SIF | 352x288 | 352x240 1/2 D1 | 352x576 | 352x480 2/3 D1 | 480x576 | 480x480 D1 | 720x576 | 720x480 */ dist_352 = abs(f->fmt.pix.width - 352); dist_480 = abs(f->fmt.pix.width - 480); dist_720 = abs(f->fmt.pix.width - 720); if (dist_720 < dist_480) { f->fmt.pix.width = 720; f->fmt.pix.height = 576; h->video_format = SAA6752HS_VF_D1; } else if (dist_480 < dist_352) { f->fmt.pix.width = 480; f->fmt.pix.height = 576; h->video_format = SAA6752HS_VF_2_3_D1; } else { f->fmt.pix.width = 352; if (abs(f->fmt.pix.height - 576) < abs(f->fmt.pix.height - 288)) { f->fmt.pix.height = 576; h->video_format = SAA6752HS_VF_1_2_D1;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -