fixed a problem in negotiating image resolution and pixel format, fixed jpeg decoding

This commit is contained in:
niels
2013-09-23 20:16:34 +02:00
parent a778cba1be
commit 283e05de05

View File

@@ -118,7 +118,7 @@ typedef struct
int frames_done[N_FRAMES]; int frames_done[N_FRAMES];
int frameidx; int frameidx;
int frame_ready; int frame_ready;
uint8_t *tmpbuf; uint8_t *tmpbuf[3];
int is_streaming; int is_streaming;
int pause_read; int pause_read;
int pause_capture; int pause_capture;
@@ -483,7 +483,7 @@ static void v4l2_enum_frame_sizes( v4l2info *v )
} }
} }
static int v4l2_tryout_pixel_format( v4l2info *v, int pf, int w, int h ) static int v4l2_tryout_pixel_format( v4l2info *v, int pf, int w, int h, int *src_w, int *src_h, int *src_pf )
{ {
struct v4l2_format format; struct v4l2_format format;
memset( &format, 0, sizeof(format)); memset( &format, 0, sizeof(format));
@@ -518,14 +518,18 @@ static int v4l2_tryout_pixel_format( v4l2info *v, int pf, int w, int h )
return 0; return 0;
} }
veejay_msg(VEEJAY_MSG_INFO,"v4l2: Device supports capture in %4.4s (%dx%d)", veejay_msg(VEEJAY_MSG_DEBUG,"v4l2: Query %dx%d in %d, device supports capture in %4.4s (%dx%d)",
w,h,pf,
(char*) &format.fmt.pix.pixelformat, (char*) &format.fmt.pix.pixelformat,
format.fmt.pix.width, format.fmt.pix.width,
format.fmt.pix.height format.fmt.pix.height
); );
*src_w = format.fmt.pix.width;
*src_h = format.fmt.pix.height;
*src_pf = format.fmt.pix.pixelformat;
return 1; return ( pf == format.fmt.pix.pixelformat);
} }
static void v4l2_setup_jpeg_capture(v4l2info *v, int wid, int hei) static void v4l2_setup_jpeg_capture(v4l2info *v, int wid, int hei)
@@ -535,7 +539,11 @@ static void v4l2_setup_jpeg_capture(v4l2info *v, int wid, int hei)
jpegcomp.jpeg_markers |= V4L2_JPEG_MARKER_DQT; // DQT jpegcomp.jpeg_markers |= V4L2_JPEG_MARKER_DQT; // DQT
ioctl(v->fd, VIDIOC_S_JPEGCOMP, &jpegcomp); ioctl(v->fd, VIDIOC_S_JPEGCOMP, &jpegcomp);
v->is_jpeg = 1; v->is_jpeg = 1;
v->tmpbuf = (uint8_t*) vj_malloc(sizeof(uint8_t) * wid * hei * 3 ); veejay_msg(VEEJAY_MSG_DEBUG, "v4l2: configure temporary buffer for jpeg decoding: %dx%d" , wid,hei );
v->tmpbuf[0] = (uint8_t*) vj_malloc(sizeof(uint8_t) * wid * hei * 3 );
v->tmpbuf[1] = v->tmpbuf[0] + (wid * hei);
v->tmpbuf[2] = v->tmpbuf[1] + (wid * hei);
} }
static int v4l2_setup_avcodec_capture( v4l2info *v, int wid, int hei, int codec_id ) static int v4l2_setup_avcodec_capture( v4l2info *v, int wid, int hei, int codec_id )
@@ -559,7 +567,10 @@ static int v4l2_setup_avcodec_capture( v4l2info *v, int wid, int hei, int codec_
v->picture->data[0] = vj_malloc(wid * hei + wid); v->picture->data[0] = vj_malloc(wid * hei + wid);
v->picture->data[1] = vj_malloc(wid * hei + wid); v->picture->data[1] = vj_malloc(wid * hei + wid);
v->picture->data[2] = vj_malloc(wid * hei + wid); v->picture->data[2] = vj_malloc(wid * hei + wid);
v->tmpbuf = (uint8_t*) vj_malloc(sizeof(uint8_t) * wid * hei * 3 ); v->tmpbuf[0] = (uint8_t*) vj_malloc(sizeof(uint8_t) * wid * hei * 3 );
v->tmpbuf[1] = v->tmpbuf[0] + (wid * hei);
v->tmpbuf[2] = v->tmpbuf[1] + (wid * hei);
if( v->codec->capabilities & CODEC_CAP_TRUNCATED) if( v->codec->capabilities & CODEC_CAP_TRUNCATED)
v->c->flags |= CODEC_FLAG_TRUNCATED; v->c->flags |= CODEC_FLAG_TRUNCATED;
@@ -571,66 +582,60 @@ static int v4l2_setup_avcodec_capture( v4l2info *v, int wid, int hei, int codec_
free(v->picture->data[2]); free(v->picture->data[2]);
free(v->picture); free(v->picture);
av_free(v->c); av_free(v->c);
free(v->tmpbuf); free(v->tmpbuf[0]);
return 0; return 0;
} }
return 1; return 1;
} }
static int v4l2_negotiate_pixel_format( v4l2info *v, int host_fmt, int wid, int hei, uint32_t *candidate) static int v4l2_negotiate_pixel_format( v4l2info *v, int host_fmt, int wid, int hei, uint32_t *candidate, uint32_t *dw, uint32_t *dh)
{ {
struct v4l2_format format; struct v4l2_format format;
int native_pixel_format = v4l2_ffmpeg2v4l2( host_fmt ); int native_pixel_format = v4l2_ffmpeg2v4l2( host_fmt );
char *greycap = getenv( "VEEJAY_V4L2_GREYSCALE_ONLY" ); char *greycap = getenv( "VEEJAY_V4L2_GREYSCALE_ONLY" );
//@ does user want grey scale capture //@ does user want grey scale capture
if( greycap ) { if( greycap ) {
int gc = atoi(greycap); int gc = atoi(greycap);
if( gc == 1 ) { if( gc == 1 ) {
int have_gs = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_GREY, wid,hei ); int have_gs = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_GREY, wid,hei,dw,dh, candidate );
if( have_gs ) { if( have_gs ) {
veejay_msg(VEEJAY_MSG_DEBUG, "v4l2: Setting grey scale (env)"); veejay_msg(VEEJAY_MSG_DEBUG, "v4l2: Setting grey scale (env)");
v->grey=1; v->grey=1;
*candidate = V4L2_PIX_FMT_GREY;
return 1; return 1;
} }
} }
} }
//@ does capture card support our native format //@ does capture card support our native format
int supported = v4l2_tryout_pixel_format( v, native_pixel_format, wid, hei,dw,dh,candidate );
if( supported ) {
veejay_msg(VEEJAY_MSG_DEBUG, "v4l2: Capture device supports native format" );
return 1;
}
int supported = v4l2_tryout_pixel_format( v, native_pixel_format, wid, hei );
if( supported ) {
*candidate = native_pixel_format;
return 1;
}
//@ does capture support YUYV or UYVU //@ does capture support YUYV or UYVU
supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_YUYV, wid, hei ); supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_YUYV, wid, hei,dw,dh,candidate );
if( supported ) { if( supported ) {
*candidate = V4L2_PIX_FMT_YUYV;
return 1; return 1;
} }
supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_UYVY, wid, hei ); supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_UYVY, wid, hei,dw,dh,candidate );
if( supported ) { if( supported ) {
*candidate = V4L2_PIX_FMT_UYVY;
return 1; return 1;
} }
//@ or RGB 24/32 //@ or RGB 24/32
supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_RGB24, wid, hei ); supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_RGB24, wid, hei ,dw,dh,candidate);
if( supported ) { if( supported ) {
*candidate = V4L2_PIX_FMT_RGB24;
return 1; return 1;
} }
supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_RGB32, wid, hei ); supported = v4l2_tryout_pixel_format( v, V4L2_PIX_FMT_RGB32, wid, hei,dw,dh,candidate );
if( supported ) { if( supported ) {
*candidate = V4L2_PIX_FMT_RGB32;
return 1; return 1;
} }
@@ -643,14 +648,15 @@ static int v4l2_negotiate_pixel_format( v4l2info *v, int host_fmt, int wid, int
if( v->supported_pixel_formats[k] == V4L2_PIX_FMT_JPEG ) { if( v->supported_pixel_formats[k] == V4L2_PIX_FMT_JPEG ) {
v4l2_setup_jpeg_capture( v, wid,hei ); v4l2_setup_jpeg_capture( v, wid,hei );
*candidate = V4L2_PIX_FMT_YUV420; *candidate = V4L2_PIX_FMT_JPEG;
return 1; return 1;
} }
if( v->supported_pixel_formats[k] == V4L2_PIX_FMT_MJPEG) { if( v->supported_pixel_formats[k] == V4L2_PIX_FMT_MJPEG) {
if( v4l2_setup_avcodec_capture( v, wid,hei, CODEC_ID_MJPEG ) == 0 ) if( v4l2_setup_avcodec_capture( v, wid,hei, CODEC_ID_MJPEG ) == 0 )
continue; continue;
*candidate = V4L2_PIX_FMT_YUV420; *candidate = v->supported_pixel_formats[k];
veejay_msg(VEEJAY_MSG_DEBUG, "v4l2: Using MJPEG decoder" );
return 1; return 1;
} }
@@ -670,10 +676,12 @@ static int v4l2_configure_format( v4l2info *v, int host_fmt, int wid, int hei )
struct v4l2_format format; struct v4l2_format format;
uint32_t cap_pf = 0; uint32_t cap_pf = 0;
uint32_t src_wid = 0;
uint32_t src_hei = 0;
memset( &format, 0, sizeof(format)); memset( &format, 0, sizeof(format));
int res = v4l2_negotiate_pixel_format(v, host_fmt, wid, hei, &cap_pf ); int res = v4l2_negotiate_pixel_format(v, host_fmt, wid, hei, &cap_pf, &src_wid, &src_hei );
if( res == 0 ) { if( res == 0 ) {
veejay_msg(VEEJAY_MSG_ERROR, "v4l2: sorry but I don't know how to handle your capture device just yet!"); veejay_msg(VEEJAY_MSG_ERROR, "v4l2: sorry but I don't know how to handle your capture device just yet!");
@@ -682,18 +690,26 @@ static int v4l2_configure_format( v4l2info *v, int host_fmt, int wid, int hei )
if( res == 1 ) { if( res == 1 ) {
v->format.fmt.pix.pixelformat = cap_pf; v->format.fmt.pix.pixelformat = cap_pf;
v->format.fmt.pix.width = wid; v->format.fmt.pix.width = src_wid;
v->format.fmt.pix.height = hei; v->format.fmt.pix.height = src_hei;
v->info = yuv_yuv_template( NULL,NULL,NULL,wid, hei, v->info = yuv_yuv_template( NULL,NULL,NULL,src_wid, src_hei,
v4l2_pixelformat2ffmpeg( cap_pf ) ); v4l2_pixelformat2ffmpeg( cap_pf ) );
yuv_plane_sizes( v->info, &(v->planes[0]),&(v->planes[1]),&(v->planes[2]),&(v->planes[3]) ); yuv_plane_sizes( v->info, &(v->planes[0]),&(v->planes[1]),&(v->planes[2]),&(v->planes[3]) );
veejay_msg(VEEJAY_MSG_INFO, "v4l2: Final configuration is in %s (%dx%d)", veejay_msg(VEEJAY_MSG_INFO, "v4l2: Using scaler, destination format is in %s (%dx%d), source is in %dx%d",
(char*) &cap_pf, (char*) &cap_pf,
wid, wid,
hei ); hei, src_wid,src_hei );
if( cap_pf == V4L2_PIX_FMT_JPEG ) {
v->info->data[0] = v->tmpbuf[0];
v->info->data[1] = v->tmpbuf[1];
v->info->data[2] = v->tmpbuf[2];
}
return 1; return 1;
} }
@@ -1141,52 +1157,45 @@ static int v4l2_pull_frame_intern( v4l2info *v )
int got_picture = 0; int got_picture = 0;
switch(v->is_jpeg) { if(!v->is_jpeg)
case 1: v4l2_set_output_pointers( v,src );
#ifdef HAVE_JPEG
v4l2_set_output_pointers(v,v->tmpbuf);
length = decode_jpeg_raw( src, n, 0,0, v->info->width,v->info->height,v->info->data[0],v->info->data[1],v->info->data[2] );
if( length == 0 ) { //@ success
length = 1;
}
#else
veejay_msg(0, "v4l2: veejay was compiled without libjpeg");
return 0;
#endif
break;
case 2:
// length = avcodec_decode_video( v->c, v->picture, &got_picture, v->tmpbuf,src );
length = -1;
if( length == -1 ) {
veejay_msg(0,"v4l2: error while decoding frame");
return 0;
}
v->info->data[0] = v->picture->data[0];
v->info->data[1] = v->picture->data[1];
v->info->data[2] = v->picture->data[2];
break; if( v->scaler == NULL )
default: {
v4l2_set_output_pointers(v,src); sws_template templ;
break; memset(&templ,0,sizeof(sws_template));
templ.flags = yuv_which_scaler();
v->scaler = yuv_init_swscaler( v->info,v->frames[ 0 ], &templ, yuv_sws_get_cpu_flags() );
} }
if( v->scaler == NULL ) if( v->is_jpeg == 1 ) {
{ length = decode_jpeg_raw( src, n, 0,0, v->info->width,v->info->height,v->info->data[0],v->info->data[1],v->info->data[2] );
sws_template templ; if( length == 0 ) { //@ success
memset(&templ,0,sizeof(sws_template)); length = 1;
templ.flags = yuv_which_scaler();
v->scaler = yuv_init_swscaler( v->info,v->frames[ 0 ], &templ, yuv_sws_get_cpu_flags() );
} }
} else if( v->is_jpeg == 2 ) {
yuv_convert_and_scale( v->scaler, v->info, v->frames[ v->frameidx ] ); AVPacket pkt;
veejay_memset( &pkt, 0, sizeof(AVPacket));
lock_(v->video_info); pkt.data = src;
pkt.size = n;
length = avcodec_decode_video2( v->c, v->picture, &got_picture, &pkt );
if( length == -1 ) {
veejay_msg(0,"v4l2: error while decoding mjpeg frame");
}
v->info->data[0] = v->picture->data[0];
v->info->data[1] = v->picture->data[1];
v->info->data[2] = v->picture->data[2];
}
yuv_convert_and_scale( v->scaler, v->info, v->frames[ v->frameidx ] );
lock_(v->video_info);
v->frames_done[v->frameidx] = 1; v->frames_done[v->frameidx] = 1;
v->frame_ready = v->frameidx; v->frame_ready = v->frameidx;
v->frameidx = (v->frameidx + 1) % N_FRAMES; v->frameidx = (v->frameidx + 1) % N_FRAMES;
unlock_(v->video_info); unlock_(v->video_info);
signal_(v->video_info); signal_(v->video_info);
if(!v->rw) { if(!v->rw) {
if( -1 == vioctl( v->fd, VIDIOC_QBUF, &(v->buffer))) { if( -1 == vioctl( v->fd, VIDIOC_QBUF, &(v->buffer))) {
@@ -1252,36 +1261,41 @@ int v4l2_pull_frame(void *vv,VJFrame *dst)
int got_picture = 0; int got_picture = 0;
switch(v->is_jpeg) { if(!v->is_jpeg)
#ifdef HAVE_JPEG v4l2_set_output_pointers( v,src );
case 1:
v4l2_set_output_pointers(v,v->tmpbuf);
length = decode_jpeg_raw( src, n, 0,0, v->info->width,v->info->height,v->info->data[0],v->info->data[1],v->info->data[2] );
if( length == 0 ) { //@ success
length = 1;
}
break;
#endif
case 2:
//length = avcodec_decode_video( v->c, v->picture, &got_picture, v->tmpbuf,src );
length = -1;
if( length == -1 ) {
veejay_msg(0,"v4l2: error while decoding frame");
return 0;
}
v->info->data[0] = v->picture->data[0];
v->info->data[1] = v->picture->data[1];
v->info->data[2] = v->picture->data[2];
break; if( v->scaler == NULL )
default: {
v4l2_set_output_pointers(v,src); sws_template templ;
break; memset(&templ,0,sizeof(sws_template));
templ.flags = yuv_which_scaler();
v->scaler = yuv_init_swscaler( v->info,v->frames[ 0 ], &templ, yuv_sws_get_cpu_flags() );
} }
if( v->is_jpeg == 1 ) {
length = decode_jpeg_raw( src, n, 0,0, v->info->width,v->info->height,v->info->data[0],v->info->data[1],v->info->data[2] );
if( length == 0 ) { //@ success
length = 1;
}
} else if( v->is_jpeg ==2 ) {
AVPacket pkt;
veejay_memset( &pkt, 0, sizeof(AVPacket));
pkt.data = src;
pkt.size = n;
length = avcodec_decode_video2( v->c, v->picture, &got_picture, &pkt );
if( length == -1 ) {
veejay_msg(0,"v4l2: error while decoding frame");
}
v->info->data[0] = v->picture->data[0];
v->info->data[1] = v->picture->data[1];
v->info->data[2] = v->picture->data[2];
}
yuv_convert_and_scale( v->scaler, v->info, v->frames[ v->frameidx ] );
if( length > 0 ) {
yuv_convert_and_scale( v->scaler, v->info, dst );
}
if(!v->rw) { if(!v->rw) {
if( -1 == vioctl( v->fd, VIDIOC_QBUF, &(v->buffer))) { if( -1 == vioctl( v->fd, VIDIOC_QBUF, &(v->buffer))) {
veejay_msg(0, "v4l2: VIDIOC_QBUF failed with %s", strerror(errno)); veejay_msg(0, "v4l2: VIDIOC_QBUF failed with %s", strerror(errno));
@@ -1338,8 +1352,8 @@ void v4l2_close( void *d )
if(v->c) { if(v->c) {
av_free(v->c); av_free(v->c);
} }
if(v->tmpbuf) { if(v->tmpbuf[0]) {
free(v->tmpbuf); free(v->tmpbuf[0]);
} }
if(v->codec) { if(v->codec) {