> > After this change, things are working, but I still have a little > > problem: in my setup, I first run a program that opens /dev/video1, does > > some ioctl() to configure the stream, and exits; then I run a different > > program that opens /dev/video1 for reading. With your patch, this does > > not work because when the second program starts to read from /dev/video1 > > saa6752hs_init() is called with params == NULL, hence it restores all > > the parameters to the default. I think that adding a > > i2c_set_clientdata(client, cachedParams); > > at the end of saa6752hs_init() fixes this problem (at least, it works > > for me, but I don't know if it is the correct thing to do -- I do not > > know the i2c stuff well). > > Hmm, its supposed to be able to support that (I do something similar). When > its called with (params!=NULL), it copies them into the cachedParams. When > its called with (params==NULL), it just uses the cachedParams, as set by > the previous call. Must be an annoying bug somewhere - I'll see if I can > spot it.
Hi, found a problem - I had the check for target bitrate and max bit rate the wrong way round. Oh, I've also added in that printk we were talking about - moan if MPEG_SETPARAMS fails since we send the return code to the user app. Just tested it with a quick program - seems to be preserving the mpeg settings across multiple open() calls now.
Common subdirectories: saa7134-0.2.12.orig/.tmp_versions and saa7134-0.2.12/.tmp_versions Common subdirectories: saa7134-0.2.12.orig/doc and saa7134-0.2.12/doc Common subdirectories: saa7134-0.2.12.orig/linux and saa7134-0.2.12/linux Common subdirectories: saa7134-0.2.12.orig/media and saa7134-0.2.12/media diff -Nau saa7134-0.2.12.orig/saa6752hs.c saa7134-0.2.12/saa6752hs.c --- saa7134-0.2.12.orig/saa6752hs.c 2004-02-22 01:59:35.000000000 +0000 +++ saa7134-0.2.12/saa6752hs.c 2004-05-17 16:07:44.454938784 +0100 @@ -11,6 +11,7 @@ #include <linux/types.h> #include <linux/videodev.h> #include <linux/init.h> +#include <linux/crc32.h> #if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0) #include "i2c-compat.h" @@ -73,9 +74,9 @@ 0x00, 0x01, // program_number(1) - 0xe0, 0x10, // PMT PID(0x10) + 0xe0, 0x00, // PMT PID - 0x76, 0xf1, 0x44, 0xd1 // CRC32 + 0x00, 0x00, 0x00, 0x00 // CRC32 }; static u8 PMT[] = { @@ -83,7 +84,7 @@ 0x01, // table number for encoder 0x47, // sync - 0x40, 0x10, // transport_error_indicator(0), payload_unit_start(1), transport_priority(0), pid(0x10) + 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 @@ -97,22 +98,27 @@ 0x00, 0x00, // section_number(0), last_section_number(0) - 0xe1, 0x04, // PCR_PID (0x104) + 0xe0, 0x00, // PCR_PID 0xf0, 0x00, // program_info_length(0) - 0x02, 0xe1, 0x00, 0xf0, 0x00, // video stream type(2), pid(0x100) - 0x04, 0xe1, 0x03, 0xf0, 0x00, // audio stream type(4), pid(0x103) + 0x02, 0xe0, 0x00, 0xf0, 0x00, // video stream type(2), pid + 0x04, 0xe0, 0x00, 0xf0, 0x00, // audio stream type(4), pid - 0xa1, 0xca, 0x0f, 0x82 // CRC32 + 0x00, 0x00, 0x00, 0x00 // CRC32 }; static struct mpeg_params mpeg_params_template = { - .bitrate_mode = MPEG_BITRATE_MODE_CBR, - .video_target_bitrate = 5000, + .video_bitrate_mode = MPEG_VIDEO_BITRATE_MODE_VBR, + .video_target_bitrate = 4000, + .video_max_bitrate = 6000, .audio_bitrate = MPEG_AUDIO_BITRATE_256, - .total_bitrate = 6000, + .total_bitrate = 7000, + .pmt_pid = 16, + .video_pid = 260, + .audio_pid = 256, + .pcr_pid = 259, }; @@ -133,7 +139,7 @@ break; case SAA6752HS_COMMAND_STOP: - buf[0] = 0x03; + buf[0] = 0x03; break; case SAA6752HS_COMMAND_START: @@ -197,11 +203,11 @@ // set the bitrate mode buf[0] = 0x71; - buf[1] = params->bitrate_mode; + buf[1] = params->video_bitrate_mode; i2c_master_send(client, buf, 2); // set the video bitrate - if (params->bitrate_mode == MPEG_BITRATE_MODE_VBR) { + if (params->video_bitrate_mode == MPEG_VIDEO_BITRATE_MODE_VBR) { // set the target bitrate buf[0] = 0x80; buf[1] = params->video_target_bitrate >> 8; @@ -239,25 +245,73 @@ static int saa6752hs_init(struct i2c_client* client, struct mpeg_params* params) { unsigned char buf[3]; - void *data; + struct mpeg_params* cachedParams; + u32 crc; + unsigned char localPAT[256]; + unsigned char localPMT[256]; + + // grab the previous set of parameters + cachedParams = (struct mpeg_params*) i2c_get_clientdata(client); // check the bitrate parameters first if (params != NULL) { - if (params->bitrate_mode >= MPEG_BITRATE_MODE_MAX) + unsigned int pmt_pid = 0, pcr_pid = 0, video_pid = 0 , audio_pid = 0; + + // check supplied params are valid + if (params->video_bitrate_mode >= MPEG_VIDEO_BITRATE_MODE_MAX) return -EINVAL; if (params->video_target_bitrate >= MPEG_VIDEO_TARGET_BITRATE_MAX) return -EINVAL; - if (params->video_max_bitrate >= MPEG_VIDEO_MAX_BITRATE_MAX) - return -EINVAL; if (params->audio_bitrate >= MPEG_AUDIO_BITRATE_MAX) return -EINVAL; if (params->total_bitrate >= MPEG_TOTAL_BITRATE_MAX) return -EINVAL; - if (params->bitrate_mode == MPEG_BITRATE_MODE_MAX && - params->video_target_bitrate <= params->video_max_bitrate) - return -EINVAL; + if (params->video_bitrate_mode == MPEG_VIDEO_BITRATE_MODE_VBR) { + if (params->video_max_bitrate >= MPEG_VIDEO_MAX_BITRATE_MAX) + return -EINVAL; + if (params->video_target_bitrate >= params->video_max_bitrate) + return -EINVAL; + } + if (params->pmt_pid != 0) { + if (params->pmt_pid > MPEG_PID_MAX) + return -EINVAL; + pmt_pid = params->pmt_pid; + } else { + pmt_pid = cachedParams->pmt_pid; + } + if (params->pcr_pid != 0) { + if (params->pcr_pid > MPEG_PID_MAX) + return -EINVAL; + pcr_pid = params->pcr_pid; + } else { + pcr_pid = cachedParams->pcr_pid; + } + if (params->video_pid != 0) { + if (params->video_pid > MPEG_PID_MAX) + return -EINVAL; + video_pid = params->video_pid; + } else { + video_pid = cachedParams->video_pid; + } + if (params->audio_pid != 0) { + if (params->audio_pid > MPEG_PID_MAX) + return -EINVAL; + audio_pid = params->audio_pid; + } else { + audio_pid = cachedParams->audio_pid; + } + + // update cache + memcpy(cachedParams, params, sizeof(struct mpeg_params)); + cachedParams->pmt_pid = pmt_pid; + cachedParams->pcr_pid = pcr_pid; + cachedParams->video_pid = video_pid; + cachedParams->audio_pid = audio_pid; } - + + // set bitrate + saa6752hs_set_bitrate(client, cachedParams); + // Set GOP structure {3, 13} buf[0] = 0x72; buf[1] = 0x03; @@ -283,27 +337,55 @@ buf[0] = 0xB0; buf[1] = 0x05; i2c_master_send(client,buf,2); - - // Set Audio PID {0x103} + + /* compute PAT */ + memcpy(localPAT, PAT, sizeof(PAT)); + localPAT[17] = 0xe0 | ((cachedParams->pmt_pid >> 8) & 0x0f); + localPAT[18] = cachedParams->pmt_pid & 0xff; + crc = crc32_be(~0, &localPAT[7], sizeof(PAT) - 7 - 4); + localPAT[sizeof(PAT) - 4] = (crc >> 24) & 0xFF; + localPAT[sizeof(PAT) - 3] = (crc >> 16) & 0xFF; + localPAT[sizeof(PAT) - 2] = (crc >> 8) & 0xFF; + localPAT[sizeof(PAT) - 1] = crc & 0xFF; + + /* compute PMT */ + memcpy(localPMT, PMT, sizeof(PMT)); + localPMT[3] = 0x40 | ((cachedParams->pmt_pid >> 8) & 0x0f); + localPMT[4] = cachedParams->pmt_pid & 0xff; + localPMT[15] = 0xE0 | ((cachedParams->pcr_pid >> 8) & 0x0F); + localPMT[16] = cachedParams->pcr_pid & 0xFF; + localPMT[20] = 0xE0 | ((cachedParams->video_pid >> 8) & 0x0F); + localPMT[21] = cachedParams->video_pid & 0xFF; + localPMT[25] = 0xE0 | ((cachedParams->audio_pid >> 8) & 0x0F); + localPMT[26] = cachedParams->audio_pid & 0xFF; + crc = crc32_be(~0, &localPMT[7], sizeof(PMT) - 7 - 4); + localPMT[sizeof(PMT) - 4] = (crc >> 24) & 0xFF; + localPMT[sizeof(PMT) - 3] = (crc >> 16) & 0xFF; + localPMT[sizeof(PMT) - 2] = (crc >> 8) & 0xFF; + localPMT[sizeof(PMT) - 1] = crc & 0xFF; + + // Set Audio PID buf[0] = 0xC1; - buf[1] = 0x01; - buf[2] = 0x03; + buf[1] = (cachedParams->audio_pid >> 8) & 0xFF; + buf[2] = cachedParams->audio_pid & 0xFF; i2c_master_send(client,buf,3); - - // setup bitrate settings - data = i2c_get_clientdata(client); - if (params) { - saa6752hs_set_bitrate(client, params); - memcpy(data, params, sizeof(struct mpeg_params)); - } else { - // parameters were not supplied. use the previous set - saa6752hs_set_bitrate(client, (struct mpeg_params*) data); - } - + + // Set Video PID + buf[0] = 0xC0; + buf[1] = (cachedParams->video_pid >> 8) & 0xFF; + buf[2] = cachedParams->video_pid & 0xFF; + i2c_master_send(client,buf,3); + + // Set PCR PID + buf[0] = 0xC4; + buf[1] = (cachedParams->pcr_pid >> 8) & 0xFF; + buf[2] = cachedParams->pcr_pid & 0xFF; + i2c_master_send(client,buf,3); + // Send SI tables - i2c_master_send(client,PAT,sizeof(PAT)); - i2c_master_send(client,PMT,sizeof(PMT)); - + i2c_master_send(client,localPAT,sizeof(PAT)); + i2c_master_send(client,localPMT,sizeof(PMT)); + // mute then unmute audio. This removes buzzing artefacts buf[0] = 0xa4; buf[1] = 1; @@ -384,10 +466,14 @@ saa6752hs_command(struct i2c_client *client, unsigned int cmd, void *arg) { struct mpeg_params* init_arg = arg; + int result; switch (cmd) { case MPEG_SETPARAMS: - return saa6752hs_init(client, init_arg); + result = saa6752hs_init(client, init_arg); + if (result != 0) + printk("saa6752hs: MPEG_SETPARAMS failed: %i\n", result); + return result; default: /* nothing */ diff -Nau saa7134-0.2.12.orig/saa6752hs.h saa7134-0.2.12/saa6752hs.h --- saa7134-0.2.12.orig/saa6752hs.h 2004-02-22 01:59:35.000000000 +0000 +++ saa7134-0.2.12/saa6752hs.h 2004-05-17 11:47:13.000000000 +0100 @@ -21,11 +21,11 @@ #ifndef _SAA6752HS_H #define _SAA6752HS_H -enum mpeg_bitrate_mode { - MPEG_BITRATE_MODE_VBR = 0, /* Variable bitrate */ - MPEG_BITRATE_MODE_CBR = 1, /* Constant bitrate */ +enum mpeg_video_bitrate_mode { + MPEG_VIDEO_BITRATE_MODE_VBR = 0, /* Variable bitrate */ + MPEG_VIDEO_BITRATE_MODE_CBR = 1, /* Constant bitrate */ - MPEG_BITRATE_MODE_MAX + MPEG_VIDEO_BITRATE_MODE_MAX }; enum mpeg_audio_bitrate { @@ -38,13 +38,19 @@ #define MPEG_VIDEO_TARGET_BITRATE_MAX 27000 #define MPEG_VIDEO_MAX_BITRATE_MAX 27000 #define MPEG_TOTAL_BITRATE_MAX 27000 - +#define MPEG_PID_MAX ((1 << 14) - 1) + struct mpeg_params { - enum mpeg_bitrate_mode bitrate_mode; + enum mpeg_video_bitrate_mode video_bitrate_mode; unsigned int video_target_bitrate; unsigned int video_max_bitrate; // only used for VBR enum mpeg_audio_bitrate audio_bitrate; unsigned int total_bitrate; + + unsigned int pmt_pid; + unsigned int video_pid; + unsigned int audio_pid; + unsigned int pcr_pid; }; #define MPEG_SETPARAMS _IOW('6',100,struct mpeg_params)