Gentoo Forums
Gentoo Forums
Gentoo Forums
Quick Search: in
problem in using "mmap"
View unanswered posts
View posts from last 24 hours

 
Reply to topic    Gentoo Forums Forum Index Portage & Programming
View previous topic :: View next topic  
Author Message
lxjhjx
n00b
n00b


Joined: 21 Nov 2012
Posts: 11

PostPosted: Thu Nov 29, 2012 12:35 pm    Post subject: problem in using "mmap" Reply with quote

In a linux program code ,I use "mmap"to mmap something to the memory, but it runs errorly,,I use gdb totry to find the problem ,I find when I use mmap function, I make its parameter "NULL",so the system can automatically get the start address ,but I find the address 0xb7d90000 <Address 0xb7d90000 out of bounds>!
what can I do to slove the problem?
Back to top
View user's profile Send private message
Hu
Watchman
Watchman


Joined: 06 Mar 2007
Posts: 9061

PostPosted: Fri Nov 30, 2012 2:05 am    Post subject: Reply with quote

Please post both the strace output demonstrating the problem and the source code which calls mmap.
Back to top
View user's profile Send private message
lxjhjx
n00b
n00b


Joined: 21 Nov 2012
Posts: 11

PostPosted: Fri Nov 30, 2012 5:00 am    Post subject: Reply with quote

Hu wrote:
Please post both the strace output demonstrating the problem and the source code which calls mmap.


Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/videodev.h>
       
#define WIDTH  320
#define HEIGHT 240
#define V4L_DEVICE "/dev/video0"
#define JPG "/home/lxj/test.jpg"
#define VIDEO_PALETTE_JPEG 21
main()
{

   unsigned char* buf;
   int i,j;
   int fd;
   int re;
       FILE *fp;
   int jpgsize=25600;
   struct video_capability vcap;
   struct video_channel    vc;
   struct video_mbuf       mbuf;
   struct video_mmap       mm;

   fd = open(V4L_DEVICE, O_RDWR);
   if(fd<=0)
   {
           printf("open webcam failed");
           perror("open");
             exit(1);
   }

   if(ioctl(fd, VIDIOCGCAP, &vcap)<0)
   {
             perror("VIDIOCGCAP");
             exit(1);
   }

   fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);
    printf("maxheight=%d\n",vcap.maxheight);
    printf("maxwidth=%d\n",vcap.maxwidth);

   for(i=0;i<vcap.channels;i++)
   {
             vc.channel = i;
             if(ioctl(fd, VIDIOCGCHAN, &vc)<0)
             {
                       perror("VIDIOCGCHAN");
                       exit(1);
             }

             fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);
   }

   vc.channel =0;
  vc.norm=1;

   if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)
   {
             perror("VIDIOCSCHAN");
             exit(1);
   }

  if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)
  {
        perror("VIDIOCGMBUF");
        exit(1);
  }
   fprintf(stderr,"the frames number is %d\n",mbuf.frames);

   

  buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

   if((int)buf< 0)
   {                               
             printf("mmap failed!\n");
             perror("mmap");
             exit(1);
   }
   
   mm.frame  = 0;
   mm.height = HEIGHT;
   mm.width  = WIDTH;
   mm.format = VIDEO_PALETTE_JPEG;

   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
   {         
             printf("start getting failed");
             perror("VIDIOCMCAPTURE");
            exit(1);
   }

   if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
   {                         
             printf("finish getting failed!");
             perror("VIDIOCSYNC");
             exit(1);
   }
       if((fp=fopen(JPG,"wb"))==NULL)

     {
printf("Can   not   open   Jpg   File!");
     }

     fwrite(buf,jpgsize,1,fp);
     fclose(fp);
     
   fclose(fp);

   munmap(buf,mbuf.size);
   close(fd);
}



and the output:



Video Capture Device Name : Z-star Vimicro zc0301p
maxheight=480
maxwidth=640
Video Source (0) Name : ZC301-2
the frames number is 2
mmap failed!
mmap: Success


the program stop after the function "mmap",I use gdb to get the buf address, it is :
(unsigned char *) 0xb7d90000 <Address 0xb7d90000 out of bounds>[/code]
Back to top
View user's profile Send private message
Hu
Watchman
Watchman


Joined: 06 Mar 2007
Posts: 9061

PostPosted: Fri Nov 30, 2012 11:18 pm    Post subject: Reply with quote

lxjhjx wrote:
Code:
  buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

   if((int)buf< 0)
This is wrong. Never cast a pointer to int. On amd64, an int is smaller than a pointer, so you lose precision. Checking the value for less than zero is also wrong. In a 3/1 split, user programs can receive mappings that are less than zero and not an error. You should, as noted in the man page, compare the result to the symbolic constant MAP_FAILED.
lxjhjx wrote:
Code:
   {                               
             printf("mmap failed!\n");
             perror("mmap");
This is wrong. Calling printf can change the value of errno, in which case perror will print the wrong value. This is why your output says that mmap failed with Success.
Back to top
View user's profile Send private message
wcg
Guru
Guru


Joined: 06 Jan 2009
Posts: 588

PostPosted: Sat Dec 01, 2012 12:01 pm    Post subject: Reply with quote

Immediately after mmap():
Code:

if ((void *) buf == MAP_FAILED) {
  /* perror() or equivalent */


So
Code:

ioctl(fd, VIDIOCGMBUF, &mbuf)

initializes mbuf.size?

You can check that with a debugging printf() of mbuf.size
after the above ioctl() call and before calling mmap() to see what
mbuf.size is initialized to before passing it to mmap().

There may not really be an error here. You ran it in gdb because
your code was reporting an mmap() error that perror() does not find
an errno for. gdb is reporting the address returned by mmap() as
out-of-bounds, but that may be some misperception by gdb
that happens with MAP_SHARED. Or maybe the initialization of
mbuf.size to a sane value is not happening before calling mmap().
Whatever.

Fix the error check after mmap() and then see if it still reports
an mmap() error.
_________________
TIA
Back to top
View user's profile Send private message
steveL
Advocate
Advocate


Joined: 13 Sep 2006
Posts: 2730
Location: The Peanut Gallery

PostPosted: Sat Dec 01, 2012 3:39 pm    Post subject: Reply with quote

What the others said about MAP_FAILED, and errno changing: if you want to do anything besides simply print it, use an int e; if (some call failed) { e = errno; perror("some func"); if (e == EINVAL) .. } and so on, then you can restore errno = e before you return a failure value like NULL, or just return -e if your function returns a non-negative signed integral for success. perror is defined in POSIX not to change errno, but istr this was only made explicit recently, so as with using other system functions, I think it's best to stick to the one pattern, which is saving errno as soon as something goes wrong. (You might be using some other function like fprintf with strerror, or not even be on a Unix system, so better to get into the habit from the get-go.)

This is also more performant on modern systems, since errno is not a simple int, but eg *(errno_func) where int *errno_func(void) returns thread errno location. So accessing errno is not as simple as accessing the traditional extern int errno, which was never as simple as a conventional int in any case, and none of those are as simple as checking a local automatic. And as you've seen, errno can and will change as soon as you call some other function.

Additionally, you shouldn't cast the return value from mmap: in C, void * pointers can be assigned to (or from) any other pointer type. This usually shows up as casting the return value from malloc. This is not a good idea, as if you've forgotten to include the correct header, C will assume the function returns an int, which you then cast to a pointer (Hu already explained why that's a bad idea.) Linkage will work, since the symbol is usually in libc, but it will blow up at runtime (or not, depending on the machine: making it the kind of bug that really p*sses people off, since the package will still build, and the warnings will be lost in a build log somewhere.)

C++ requires the cast, so you sometimes see people recommend them to make code work if compiled with C++. If this is a concern, it's a much better idea to use macros for it (you already need them for extern "C" { in any event, and of course you'll be changing Standard C header names, right? ;)
Code:
if ((void *) buf == MAP_FAILED)

This is so nearly right, I feel bad for pointing out the portability aspects. Firstly, there's no need to cast buf to a void * since char * and void * are specified to be the same underlying type in C (they can both point to any object), and in C++ all pointers have the same base type. As a pattern, though this seems correct (eg if buf is an int *, there's no guarantee in C that it has the same size as a void * or char *) equality operators are defined to cast it to a void * if being compared with a void * (which is what MAP_FAILED should be):
C99 Sec 6.5.9, para 5 1256.pdf wrote:
If one operand is a pointer and the other is a null pointer constant, the null pointer constant is converted to the type of the pointer.
If one operand is a pointer to an object or incomplete type and the other is a pointer to a qualified or unqualified version of void, the former is converted to the type of the latter.

On some systems however, MAP_FAILED is not defined to be a pointer at all, believe it or not, so to be safe you should cast that instead:
Code:
if (buf == (void *)MAP_FAILED)

I can't remember which system uses plain: -1 instead of: (void *)-1 as the definition; I read about it a couple of months ago (I have to code portably for work.) It was something like AIX or HP-UX, before a particular version, one of those old ones that some people like to mock, but others respect. In any event, why worry about it, when you can make your code work everywhere that has mmap?

HTH,
steveL.
_________________
creaker wrote:
systemd. It is a really ass pain

update - "a most excellent portage wrapper"

#friendly-coders -- We're still here for you™ ;)
Back to top
View user's profile Send private message
Hu
Watchman
Watchman


Joined: 06 Mar 2007
Posts: 9061

PostPosted: Sat Dec 01, 2012 5:09 pm    Post subject: Reply with quote

steveL wrote:
Additionally, you shouldn't cast the return value from mmap: in C, void * pointers can be assigned to (or from) any other pointer type. This usually shows up as casting the return value from malloc. This is not a good idea, as if you've forgotten to include the correct header, C will assume the function returns an int, which you then cast to a pointer (Hu already explained why that's a bad idea.) Linkage will work, since the symbol is usually in libc, but it will blow up at runtime (or not, depending on the machine: making it the kind of bug that really p*sses people off, since the package will still build, and the warnings will be lost in a build log somewhere.)

C++ requires the cast, so you sometimes see people recommend them to make code work if compiled with C++. If this is a concern, it's a much better idea to use macros for it (you already need them for extern "C" { in any event, and of course you'll be changing Standard C header names, right? ;)

C++ requires the function to be properly declared, so it is guaranteed to be a compilation error to use mmap in a C++ source file without including the proper header. C can guess linkage in some cases, though as steveL points out, this is more likely to cause problems than to avoid them. C++ cannot guess linkage, because it needs to know the types for proper name mangling. For unmangled functions, like standard C library functions, it needs an extern "C" declaration to tell it not to mangle the name.

If the right compiler flags are used, a straight C program can be made to fail to compile if declarations are missing. For any new code, I highly recommend this, since it avoids the problems steveL describes above. I like to start with -Werror -Wall -Wextra, which catches many, but not all, problems. Those problems which are caught are converted to hard errors. Distributors dislike packages which use -Werror, so you may want to include a build time flag that they can use to skip the -Werror, while keeping the other flags.
Back to top
View user's profile Send private message
lxjhjx
n00b
n00b


Joined: 21 Nov 2012
Posts: 11

PostPosted: Sun Dec 02, 2012 5:21 am    Post subject: Reply with quote

Hu wrote:
lxjhjx wrote:
Code:
  buf = (unsigned char*)mmap(0, mbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);

   if((int)buf< 0)
This is wrong. Never cast a pointer to int. On amd64, an int is smaller than a pointer, so you lose precision. Checking the value for less than zero is also wrong. In a 3/1 split, user programs can receive mappings that are less than zero and not an error. You should, as noted in the man page, compare the result to the symbolic constant MAP_FAILED.
lxjhjx wrote:
Code:
   {                               
             printf("mmap failed!\n");
             perror("mmap");
This is wrong. Calling printf can change the value of errno, in which case perror will print the wrong value. This is why your output says that mmap failed with Success.



I fix my code ,the new one:
Code:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/videodev.h>
       
#define WIDTH  320
#define HEIGHT 240
#define V4L_DEVICE "/dev/video0"
#define JPG "/home/lxj/test.jpg"

main()
{

   unsigned char* buf;
   int i,j;
   int fd;
   int re;
       FILE *fp;
   int jpgsize=25600;
   struct video_capability vcap;
   struct video_picture    pic;
   struct video_channel    vc;
   struct video_mbuf       mbuf;
   struct video_mmap       mm;
   struct video_window window;
   fd = open(V4L_DEVICE, O_RDWR);
   if(fd<=0)
   {
           printf("open webcam failed");
           perror("open");
             exit(1);
   }

   if(ioctl(fd, VIDIOCGCAP, &vcap)<0)
   {
             perror("VIDIOCGCAP");
             exit(1);
   }

   fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);
    printf("maxheight=%d\n",vcap.maxheight);
    printf("maxwidth=%d\n",vcap.maxwidth);

   



   if(ioctl(fd,VIDIOCGPICT,&pic)<0)
 {
            perror("VIDIOCSPICT");
            exit (1);
 }
       printf ( "colour=%d\nBlack and white only = %d\nCapture depth=%d\nPalette in use=%d\n",pic.colour,pic.whiteness,pic.depth ,pic.palette );

    pic.brightness = 65535;
    pic.colour =65535;
    if ( ioctl ( fd,VIDIOCSPICT,&pic ) <0 )
        exit ( 0 );
    else
        {printf ( "\nset capture attributes success\n" );}




    window.x =0;
    window.y =0 ;
    window.width = 320;
    window.height =240;

    if ( ioctl ( fd,VIDIOCSWIN, &window ) ==-1 )
        printf ( " SET video_window error!\n" );
    else
        {printf ( "\nset window success\n" );}





   /*for(i=0;i<vcap.channels;i++)
   {
             vc.channel = i;
             if(ioctl(fd, VIDIOCGCHAN, &vc)<0)
             {
                       perror("VIDIOCGCHAN");
                       exit(1);
             }

             fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);
   }

   vc.channel =0;
  vc.norm=1;

   if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)
   {
             perror("VIDIOCSCHAN");
             exit(1);
   }*/
  if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)
  {
        perror("VIDIOCGMBUF");
        exit(1);
  }
   fprintf(stderr,"the frames number is %d\n",mbuf.frames);
   printf ("VIDIOCGMBUF size %d  frames %d  offets[0]=%d offsets[1]=%d\n", mbuf.size, mbuf.frames, mbuf.offsets[0], mbuf.offsets[1]);
   
    mm.width=window.width;
    mm.height=window.height;
    mm.format =pic.palette;
    mm.frame=0;
  buf = (unsigned char *)mmap(NULL, mbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

   if((void *) buf == MAP_FAILED)
   {                               
     
             perror("mmap");
             exit(1);
   }
   

   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
   {         
             printf("start getting failed");
             perror("VIDIOCMCAPTURE");
            exit(1);
   }

   if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
   {                         
             printf("finish getting failed!");
             perror("VIDIOCSYNC");
             exit(1);
   }
       if((fp=fopen(JPG,"wb"))==NULL)

     {
printf("Can   not   open   Jpg   File!");
     }

     fwrite(buf,mbuf.size,1,fp);
     fclose(fp);
     
   fclose(fp);

   munmap(buf,mbuf.size);
   close(fd);
}


It really slove the problem of"put of bounds",but has got new problems:


    [lxj@localhost ~]$ ./t
    Video Capture Device Name : Z-star Vimicro zc0301p
    maxheight=480
    maxwidth=640
    colour=0
    Black and white only = 0
    Capture depth=24
    Palette in use=4

    set capture attributes success

    set window success
    the frames number is 2
    VIDIOCGMBUF size 2457616 frames 2 offets[0]=0 offsets[1]=1228808
    *** glibc detected *** ./t: double free or corruption (top): 0x08c87008 ***
    ======= Backtrace: =========
    /lib/libc.so.6[0x9f26c5]
    /lib/libc.so.6(cfree+0x59)[0x9f2b09]
    /lib/libc.so.6(fclose+0x136)[0x9e0db6]
    ./t[0x8048a01]
    /lib/libc.so.6(__libc_start_main+0xdc)[0x99ee9c]
    ./t[0x8048561]
    ======= Memory map: ========
    002f4000-002f5000 r-xp 002f4000 00:00 0 [vdso]
    0096a000-00985000 r-xp 00000000 fd:00 1903098 /lib/ld-2.5.so
    00985000-00986000 r-xp 0001a000 fd:00 1903098 /lib/ld-2.5.so
    00986000-00987000 rwxp 0001b000 fd:00 1903098 /lib/ld-2.5.so
    00989000-00adc000 r-xp 00000000 fd:00 1903099 /lib/libc-2.5.so
    00adc000-00ade000 r-xp 00153000 fd:00 1903099 /lib/libc-2.5.so
    00ade000-00adf000 rwxp 00155000 fd:00 1903099 /lib/libc-2.5.so
    00adf000-00ae2000 rwxp 00adf000 00:00 0
    00d40000-00d4b000 r-xp 00000000 fd:00 1903110 /lib/libgcc_s-4.1.2-20080825.so.1
    00d4b000-00d4c000 rwxp 0000a000 fd:00 1903110 /lib/libgcc_s-4.1.2-20080825.so.1
    08048000-08049000 r-xp 00000000 fd:00 2392260 /home/lxj/t
    08049000-0804a000 rw-p 00000000 fd:00 2392260 /home/lxj/t
    08c87000-08ca8000 rw-p 08c87000 00:00 0 [heap]
    b7d22000-b7f7b000 rw-s 00000000 00:11 18706 /dev/video0
    b7f7b000-b7f7d000 rw-p b7f7b000 00:00 0
    b7f91000-b7f92000 rw-p b7f91000 00:00 0
    bfd36000-bfd4b000 rw-p bffe9000 00:00 0 [stack]
    已放弃
    [lxj@localhost ~




what is up?
Back to top
View user's profile Send private message
lxjhjx
n00b
n00b


Joined: 21 Nov 2012
Posts: 11

PostPosted: Sun Dec 02, 2012 5:23 am    Post subject: Reply with quote

wcg wrote:
Immediately after mmap():
Code:

if ((void *) buf == MAP_FAILED) {
  /* perror() or equivalent */


So
Code:

ioctl(fd, VIDIOCGMBUF, &mbuf)

initializes mbuf.size?

You can check that with a debugging printf() of mbuf.size
after the above ioctl() call and before calling mmap() to see what
mbuf.size is initialized to before passing it to mmap().

There may not really be an error here. You ran it in gdb because
your code was reporting an mmap() error that perror() does not find
an errno for. gdb is reporting the address returned by mmap() as
out-of-bounds, but that may be some misperception by gdb
that happens with MAP_SHARED. Or maybe the initialization of
mbuf.size to a sane value is not happening before calling mmap().
Whatever.

Fix the error check after mmap() and then see if it still reports
an mmap() error.




I fix the "mmap" problem ,but got a new problem ,I list the problem in the last reply,help me ...........
Back to top
View user's profile Send private message
Hu
Watchman
Watchman


Joined: 06 Mar 2007
Posts: 9061

PostPosted: Sun Dec 02, 2012 5:43 pm    Post subject: Reply with quote

lxjhjx wrote:
Code:
if(fd<=0)
This is wrong. Descriptor zero is a valid descriptor, and will be returned here if your program is started with descriptor zero closed. This is uncommon, but not impossible.
lxjhjx wrote:
Code:
{
           printf("open webcam failed");
           perror("open");
This is wrong. Calling printf may affect errno.
lxjhjx wrote:
Code:
fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);
    printf("maxheight=%d\n",vcap.maxheight);
    printf("maxwidth=%d\n",vcap.maxwidth);
This is strange, but not wrong. Why are you using two different streams for the same general purpose?
lxjhjx wrote:
Code:
if(ioctl(fd,VIDIOCGPICT,&pic)<0)
 {
            perror("VIDIOCSPICT");
This is confusing. You issue VIDIOCGPICT, but report VIDIOCSPICT.
lxjhjx wrote:
Code:
if ( ioctl ( fd,VIDIOCSPICT,&pic ) <0 )
        exit ( 0 );
This looks strange. Usually, ioctl returns negative on failure. As written, you silently exit with a success status on a negative result.
lxjhjx wrote:
Code:
if ( ioctl ( fd,VIDIOCSWIN, &window ) ==-1 )
        printf ( " SET video_window error!\n" );
Did you intend to continue execution even when this fails?
lxjhjx wrote:
Code:
if((void *) buf == MAP_FAILED)
Casting a char* to void* is unnecessary.
lxjhjx wrote:
Code:
if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
   {         
             printf("start getting failed");
             perror("VIDIOCMCAPTURE");
This is wrong. Calling printf may affect errno.
lxjhjx wrote:
Code:
if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
   {                         
             printf("finish getting failed!");
             perror("VIDIOCSYNC");
This is wrong. Calling printf may affect errno.
lxjhjx wrote:
Code:
if((fp=fopen(JPG,"wb"))==NULL)

     {
printf("Can   not   open   Jpg   File!");
     }
This is wrong. You do not return or exit on failure, so if the open fails, then you pass a NULL pointer to fwrite.
lxjhjx wrote:
Code:
fwrite(buf,mbuf.size,1,fp);
You should check the return value of fwrite.
lxjhjx wrote:
Code:
fclose(fp);
     
   fclose(fp);
This is very wrong. You should close the file once, not twice.
Back to top
View user's profile Send private message
lxjhjx
n00b
n00b


Joined: 21 Nov 2012
Posts: 11

PostPosted: Mon Dec 03, 2012 6:37 am    Post subject: Reply with quote

Hu wrote:
lxjhjx wrote:
Code:
if(fd<=0)
This is wrong. Descriptor zero is a valid descriptor, and will be returned here if your program is started with descriptor zero closed. This is uncommon, but not impossible.
lxjhjx wrote:
Code:
{
           printf("open webcam failed");
           perror("open");
This is wrong. Calling printf may affect errno.
lxjhjx wrote:
Code:
fprintf(stderr,"Video Capture Device Name : %s\n",vcap.name);
    printf("maxheight=%d\n",vcap.maxheight);
    printf("maxwidth=%d\n",vcap.maxwidth);
This is strange, but not wrong. Why are you using two different streams for the same general purpose?
lxjhjx wrote:
Code:
if(ioctl(fd,VIDIOCGPICT,&pic)<0)
 {
            perror("VIDIOCSPICT");
This is confusing. You issue VIDIOCGPICT, but report VIDIOCSPICT.
lxjhjx wrote:
Code:
if ( ioctl ( fd,VIDIOCSPICT,&pic ) <0 )
        exit ( 0 );
This looks strange. Usually, ioctl returns negative on failure. As written, you silently exit with a success status on a negative result.
lxjhjx wrote:
Code:
if ( ioctl ( fd,VIDIOCSWIN, &window ) ==-1 )
        printf ( " SET video_window error!\n" );
Did you intend to continue execution even when this fails?
lxjhjx wrote:
Code:
if((void *) buf == MAP_FAILED)
Casting a char* to void* is unnecessary.
lxjhjx wrote:
Code:
if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
   {         
             printf("start getting failed");
             perror("VIDIOCMCAPTURE");
This is wrong. Calling printf may affect errno.
lxjhjx wrote:
Code:
if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
   {                         
             printf("finish getting failed!");
             perror("VIDIOCSYNC");
This is wrong. Calling printf may affect errno.
lxjhjx wrote:
Code:
if((fp=fopen(JPG,"wb"))==NULL)

     {
printf("Can   not   open   Jpg   File!");
     }
This is wrong. You do not return or exit on failure, so if the open fails, then you pass a NULL pointer to fwrite.
lxjhjx wrote:
Code:
fwrite(buf,mbuf.size,1,fp);
You should check the return value of fwrite.
lxjhjx wrote:
Code:
fclose(fp);
     
   fclose(fp);
This is very wrong. You should close the file once, not twice.



oh,so many unnessecery problem ,I fix all ,and I can get a file named: test.jpg,but it cannot be opened,what is up? the fixed code:
Code:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <errno.h>
#include <linux/videodev.h>
       
#define WIDTH  320
#define HEIGHT 240
#define V4L_DEVICE "/dev/video0"
#define JPG "/home/lxj/test.jpg"

main()
{

   unsigned char* buf;
   int i,j;
   int fd;
   int re;
       FILE *fp;
   int jpgsize=25600;
   struct video_capability vcap;
   struct video_picture    pic;
   struct video_channel    vc;
   struct video_mbuf       mbuf;
   struct video_mmap       mm;
   struct video_window window;
   fd = open(V4L_DEVICE, O_RDWR);
   if(fd<=0)
   {
           perror("open");
             exit(1);
   }

   if(ioctl(fd, VIDIOCGCAP, &vcap)<0)
   {
             perror("VIDIOCGCAP");
             exit(1);
   }

    printf("maxheight=%d\n",vcap.maxheight);
    printf("maxwidth=%d\n",vcap.maxwidth);

   



   if(ioctl(fd,VIDIOCGPICT,&pic)<0)
 {
            perror("VIDIOCGPICT");
            exit (1);
 }
       printf ( "colour=%d\nBlack and white only = %d\nCapture depth=%d\nPalette in use=%d\n",pic.colour,pic.whiteness,pic.depth ,pic.palette );

    pic.brightness = 65535;
    pic.colour =65535;
    if ( ioctl ( fd,VIDIOCSPICT,&pic ) <0 )
        exit ( 1 );
    else
        {printf ( "\nset capture attributes success\n" );}




    window.x =0;
    window.y =0 ;
    window.width = 320;
    window.height =240;

    if ( ioctl ( fd,VIDIOCSWIN, &window ) ==-1 )
       { printf ( " SET video_window error!\n" );
                       exit(1);}
    else
        {printf ( "\nset window success\n" );}





   /*for(i=0;i<vcap.channels;i++)
   {
             vc.channel = i;
             if(ioctl(fd, VIDIOCGCHAN, &vc)<0)
             {
                       perror("VIDIOCGCHAN");
                       exit(1);
             }

             fprintf(stderr,"Video Source (%d) Name : %s\n",i, vc.name);
   }

   vc.channel =0;
  vc.norm=1;

   if(ioctl(fd, VIDIOCSCHAN, &vc) < 0)
   {
             perror("VIDIOCSCHAN");
             exit(1);
   }*/
  if(ioctl(fd, VIDIOCGMBUF, &mbuf) < 0)
  {
        perror("VIDIOCGMBUF");
        exit(1);
  }
   fprintf(stderr,"the frames number is %d\n",mbuf.frames);
   printf ("VIDIOCGMBUF size %d  frames %d  offets[0]=%d offsets[1]=%d\n", mbuf.size, mbuf.frames, mbuf.offsets[0], mbuf.offsets[1]);
   
    mm.width=window.width;
    mm.height=window.height;
    mm.format =pic.palette;
    mm.frame=0;
  buf = (unsigned char *)mmap(NULL, mbuf.size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);

   if((char *) buf == MAP_FAILED)
   {                               
     
             perror("mmap");
             exit(1);
   }
   

   if(ioctl(fd, VIDIOCMCAPTURE, &mm)<0)
   {         
           
             perror("VIDIOCMCAPTURE");
            exit(1);
   }

   if(ioctl(fd, VIDIOCSYNC, &mm.frame)<0)
   {                         
             
             perror("VIDIOCSYNC");
             exit(1);
   }
       if((fp=fopen(JPG,"wb"))==NULL)

     {
printf("Can   not   open   Jpg   File!");
exit(1);
     }

     fwrite(buf,jpgsize,3*380,fp);
     fclose(fp);
     


   munmap(buf,mbuf.size);
   close(fd);
}


friend ,help me again please,thank you !
Back to top
View user's profile Send private message
wcg
Guru
Guru


Joined: 06 Jan 2009
Posts: 588

PostPosted: Mon Dec 03, 2012 5:30 pm    Post subject: Reply with quote

(Referring to other poster's comments)
Code:

-  if(fd<=0) {
+ if(fd < 0) {


Code:

-  if ((char *) buf == MAP_FAILED) {
+ if (buf == MAP_FAILED) {


First change: open() returns -1 on error, so you only need to test
that fd is less than 0 to see if there was an open() error.

Second change: the cast of buf (declared as char *) is unneeded,
because MAP_FAILED is defined to be void * (in /usr/include/sys/mman.h
on Gentoo), and C rules force buf to be evaluated as void *, too,
when testing with "==" against another void *.

Does the JPG file already exist? If so, what is its mode (what are its
permissions)? What are the permissions of the /home/lxj/ directory?

fopen() can fail on malloc() errors, too (it allocates a buffer for
a FILE * behind the scenes), if you have reached the memory
limit on your system or for your user, if the internal malloc()
tables in your process have been corrupted by some previous
bug, and so on. One thing you can try is to simply open() the JPG
file first, getting a file descriptor for it, then fdopen(), using that
returned file descriptor as an argument to fdopen(), to get a FILE *.

That would tell you whether you can open() that JPG
pathname at all.

(For a safer alternative to perror(), see libiberty's xstrerror() in the
binutils or gcc sources.)
_________________
TIA
Back to top
View user's profile Send private message
Display posts from previous:   
Reply to topic    Gentoo Forums Forum Index Portage & Programming All times are GMT
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum