| 59 | | |
|---|
| | 87 | #define IOMETHOD_TEXT N_( "IO Method" ) |
|---|
| | 88 | #define IOMETHOD_LONGTEXT N_( \ |
|---|
| | 89 | "IO Method (READ, MMAP, USERPTR)." ) |
|---|
| | 90 | #define FPS_TEXT N_( "Framerate" ) |
|---|
| | 91 | #define FPS_LONGTEXT N_( "Framerate to capture, if applicable " \ |
|---|
| | 92 | "(-1 for autodetect)." ) |
|---|
| | 93 | #define STEREO_TEXT N_( "Stereo" ) |
|---|
| | 94 | #define STEREO_LONGTEXT N_( \ |
|---|
| | 95 | "Capture the audio stream in stereo." ) |
|---|
| | 96 | #define SAMPLERATE_TEXT N_( "Samplerate" ) |
|---|
| | 97 | #define SAMPLERATE_LONGTEXT N_( \ |
|---|
| | 98 | "Samplerate of the captured audio stream, in Hz (eg: 11025, 22050, 44100, 48000)" ) |
|---|
| | 99 | #define CACHING_TEXT N_("Caching value in ms") |
|---|
| | 100 | #define CACHING_LONGTEXT N_( \ |
|---|
| | 101 | "Caching value for V4L2 captures. This " \ |
|---|
| | 102 | "value should be set in milliseconds." ) |
|---|
| | 103 | |
|---|
| | 104 | typedef enum { |
|---|
| | 105 | IO_METHOD_READ, |
|---|
| | 106 | IO_METHOD_MMAP, |
|---|
| | 107 | IO_METHOD_USERPTR, |
|---|
| | 108 | } io_method; |
|---|
| | 109 | |
|---|
| | 110 | static int i_standards_list[] = |
|---|
| | 111 | { V4L2_STD_UNKNOWN, V4L2_STD_SECAM, V4L2_STD_PAL, V4L2_STD_NTSC }; |
|---|
| | 112 | static const char *psz_standards_list_text[] = |
|---|
| | 113 | { N_("Default"), N_("SECAM"), N_("PAL"), N_("NTSC") }; |
|---|
| | 114 | |
|---|
| | 115 | static int i_iomethod_list[] = |
|---|
| | 116 | { IO_METHOD_READ, IO_METHOD_MMAP, IO_METHOD_USERPTR }; |
|---|
| | 117 | static const char *psz_iomethod_list_text[] = |
|---|
| | 118 | { N_("READ"), N_("MMAP"), N_("USERPTR") }; |
|---|
| 84 | | static int ProbeDev( demux_t * ); |
|---|
| 85 | | static int OpenVideoDev( demux_t * ); |
|---|
| | 161 | static int Demux( demux_t * ); |
|---|
| | 162 | static block_t* GrabVideo( demux_t *p_demux ); |
|---|
| | 163 | static block_t* ProcessVideoFrame( demux_t *p_demux, uint8_t *p_frame ); |
|---|
| | 164 | static block_t* GrabAudio( demux_t *p_demux ); |
|---|
| | 165 | |
|---|
| | 166 | vlc_bool_t IsChromaSupported( demux_t *p_demux, unsigned int i_v4l2 ); |
|---|
| | 167 | unsigned int GetChromaFromFourcc( char *psz_fourcc ); |
|---|
| | 168 | |
|---|
| | 169 | static int OpenVideoDev( demux_t *, char *psz_device ); |
|---|
| | 170 | static int OpenAudioDev( demux_t *, char *psz_device ); |
|---|
| | 171 | static vlc_bool_t ProbeVideoDev( demux_t *, char *psz_device ); |
|---|
| | 172 | static vlc_bool_t ProbeAudioDev( demux_t *, char *psz_device ); |
|---|
| | 173 | |
|---|
| | 174 | static struct |
|---|
| | 175 | { |
|---|
| | 176 | unsigned int i_v4l2; |
|---|
| | 177 | int i_fourcc; |
|---|
| | 178 | } v4l2chroma_to_fourcc[] = |
|---|
| | 179 | { |
|---|
| | 180 | { V4L2_PIX_FMT_GREY, VLC_FOURCC( 'G', 'R', 'E', 'Y' ) }, |
|---|
| | 181 | { V4L2_PIX_FMT_HI240, VLC_FOURCC( 'I', '2', '4', '0' ) }, |
|---|
| | 182 | { V4L2_PIX_FMT_RGB565, VLC_FOURCC( 'R', 'V', '1', '6' ) }, |
|---|
| | 183 | { V4L2_PIX_FMT_RGB555, VLC_FOURCC( 'R', 'V', '1', '5' ) }, |
|---|
| | 184 | { V4L2_PIX_FMT_BGR24, VLC_FOURCC( 'R', 'V', '2', '4' ) }, |
|---|
| | 185 | { V4L2_PIX_FMT_BGR32, VLC_FOURCC( 'R', 'V', '3', '2' ) }, |
|---|
| | 186 | { V4L2_PIX_FMT_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', '2' ) }, |
|---|
| | 187 | { V4L2_PIX_FMT_YUYV, VLC_FOURCC( 'Y', 'U', 'Y', 'V' ) }, |
|---|
| | 188 | { V4L2_PIX_FMT_UYVY, VLC_FOURCC( 'U', 'Y', 'V', 'Y' ) }, |
|---|
| | 189 | { V4L2_PIX_FMT_Y41P, VLC_FOURCC( 'I', '4', '1', 'N' ) }, |
|---|
| | 190 | { V4L2_PIX_FMT_YUV422P, VLC_FOURCC( 'I', '4', '2', '2' ) }, |
|---|
| | 191 | { V4L2_PIX_FMT_YVU420, VLC_FOURCC( 'I', '4', '2', '0' ) }, |
|---|
| | 192 | { V4L2_PIX_FMT_YUV411P, VLC_FOURCC( 'I', '4', '1', '1' ) }, |
|---|
| | 193 | { V4L2_PIX_FMT_YUV410, VLC_FOURCC( 'I', '4', '1', '0' ) }, |
|---|
| | 194 | { 0, 0 } |
|---|
| | 195 | }; |
|---|
| | 196 | |
|---|
| | 197 | struct buffer_t |
|---|
| | 198 | { |
|---|
| | 199 | void * start; |
|---|
| | 200 | size_t length; |
|---|
| | 201 | }; |
|---|
| 135 | | |
|---|
| 136 | | p_sys->psz_device = var_CreateGetString( p_demux, "v4l2-dev" ); |
|---|
| 137 | | |
|---|
| 138 | | if( ProbeDev( p_demux ) < 0 ) return VLC_EGENERIC; |
|---|
| 139 | | |
|---|
| 140 | | if( OpenVideoDev( p_demux ) < 0 ) return VLC_EGENERIC; |
|---|
| | 287 | |
|---|
| | 288 | p_sys->i_video_pts = -1; |
|---|
| | 289 | |
|---|
| | 290 | var_Create( p_demux, "v4l2-standard", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); |
|---|
| | 291 | var_Get( p_demux, "v4l2-standard", &val ); |
|---|
| | 292 | p_sys->i_selected_standard_id = i_standards_list[val.i_int]; |
|---|
| | 293 | |
|---|
| | 294 | p_sys->i_selected_input = var_CreateGetInteger( p_demux, "v4l2-input" ); |
|---|
| | 295 | |
|---|
| | 296 | p_sys->io = var_CreateGetInteger( p_demux, "v4l2-io" ); |
|---|
| | 297 | |
|---|
| | 298 | var_Create( p_demux, "v4l2-fps", VLC_VAR_FLOAT | VLC_VAR_DOINHERIT ); |
|---|
| | 299 | var_Get( p_demux, "v4l2-fps", &val ); |
|---|
| | 300 | p_sys->f_fps = val.f_float; |
|---|
| | 301 | |
|---|
| | 302 | var_Create( p_demux, "v4l2-samplerate", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT ); |
|---|
| | 303 | var_Get( p_demux, "v4l2-samplerate", &val ); |
|---|
| | 304 | p_sys->i_sample_rate = val.i_int; |
|---|
| | 305 | |
|---|
| | 306 | psz = var_CreateGetString( p_demux, "v4l2-chroma" ); |
|---|
| | 307 | p_sys->i_fourcc = GetChromaFromFourcc( psz ); |
|---|
| | 308 | free( psz ); |
|---|
| | 309 | |
|---|
| | 310 | var_Create( p_demux, "v4l2-stereo", VLC_VAR_BOOL | VLC_VAR_DOINHERIT ); |
|---|
| | 311 | var_Get( p_demux, "v4l2-stereo", &val ); |
|---|
| | 312 | p_sys->b_stereo = val.b_bool; |
|---|
| | 313 | |
|---|
| | 314 | p_sys->i_pts = var_CreateGetInteger( p_demux, "v4l2-caching" ); |
|---|
| | 315 | |
|---|
| | 316 | p_sys->psz_device = p_sys->psz_vdev = p_sys->psz_adev = NULL; |
|---|
| | 317 | p_sys->i_fd_video = -1; |
|---|
| | 318 | p_sys->i_fd_audio = -1; |
|---|
| | 319 | |
|---|
| | 320 | p_sys->p_es_video = p_sys->p_es_audio = 0; |
|---|
| | 321 | p_sys->p_block_audio = 0; |
|---|
| | 322 | |
|---|
| | 323 | ParseMRL( p_demux ); |
|---|
| | 324 | |
|---|
| | 325 | /* Find main device (video or audio) */ |
|---|
| | 326 | if( p_sys->psz_device && *p_sys->psz_device ) |
|---|
| | 327 | { |
|---|
| | 328 | msg_Dbg( p_demux, "main device='%s'", p_sys->psz_device ); |
|---|
| | 329 | |
|---|
| | 330 | /* Try to open as video device */ |
|---|
| | 331 | msg_Dbg( p_demux, "trying device '%s' as video", p_sys->psz_device ); |
|---|
| | 332 | if( ProbeVideoDev( p_demux, p_sys->psz_device ) ) |
|---|
| | 333 | { |
|---|
| | 334 | msg_Dbg( p_demux, "'%s' is a video device", p_sys->psz_device ); |
|---|
| | 335 | /* Device was a video device */ |
|---|
| | 336 | if( p_sys->psz_vdev ) free( p_sys->psz_vdev ); |
|---|
| | 337 | p_sys->psz_vdev = p_sys->psz_device; |
|---|
| | 338 | p_sys->psz_device = NULL; |
|---|
| | 339 | p_sys->i_fd_video = OpenVideoDev( p_demux, p_sys->psz_vdev ); |
|---|
| | 340 | if( p_sys->i_fd_video < 0 ) |
|---|
| | 341 | { |
|---|
| | 342 | Close( p_this ); |
|---|
| | 343 | return VLC_EGENERIC; |
|---|
| | 344 | } |
|---|
| | 345 | } |
|---|
| | 346 | else |
|---|
| | 347 | { |
|---|
| | 348 | /* Try to open as audio device */ |
|---|
| | 349 | msg_Dbg( p_demux, "trying device '%s' as audio", p_sys->psz_device ); |
|---|
| | 350 | if( ProbeAudioDev( p_demux, p_sys->psz_device ) ) |
|---|
| | 351 | { |
|---|
| | 352 | msg_Dbg( p_demux, "'%s' is an audio device", p_sys->psz_device ); |
|---|
| | 353 | /* Device was an audio device */ |
|---|
| | 354 | if( p_sys->psz_adev ) free( p_sys->psz_adev ); |
|---|
| | 355 | p_sys->psz_adev = p_sys->psz_device; |
|---|
| | 356 | p_sys->psz_device = NULL; |
|---|
| | 357 | p_sys->i_fd_audio = OpenAudioDev( p_demux, p_sys->psz_adev ); |
|---|
| | 358 | if( p_sys->i_fd_audio < 0 ) |
|---|
| | 359 | { |
|---|
| | 360 | Close( p_this ); |
|---|
| | 361 | return VLC_EGENERIC; |
|---|
| | 362 | } |
|---|
| | 363 | } |
|---|
| | 364 | } |
|---|
| | 365 | } |
|---|
| | 366 | |
|---|
| | 367 | /* If no device opened, only continue if the access was forced */ |
|---|
| | 368 | if( p_sys->i_fd_video < 0 && p_sys->i_fd_audio < 0 ) |
|---|
| | 369 | { |
|---|
| | 370 | if( strcmp( p_demux->psz_access, "v4l2" ) ) |
|---|
| | 371 | { |
|---|
| | 372 | Close( p_this ); |
|---|
| | 373 | return VLC_EGENERIC; |
|---|
| | 374 | } |
|---|
| | 375 | } |
|---|
| | 376 | |
|---|
| | 377 | /* Find video device */ |
|---|
| | 378 | if( p_sys->i_fd_video < 0 ) |
|---|
| | 379 | { |
|---|
| | 380 | if( !p_sys->psz_vdev || !*p_sys->psz_vdev ) |
|---|
| | 381 | { |
|---|
| | 382 | if( p_sys->psz_vdev ) free( p_sys->psz_vdev ); |
|---|
| | 383 | p_sys->psz_vdev = var_CreateGetString( p_demux, "v4l2-dev" );; |
|---|
| | 384 | } |
|---|
| | 385 | |
|---|
| | 386 | if( p_sys->psz_vdev && *p_sys->psz_vdev && ProbeVideoDev( p_demux, p_sys->psz_vdev ) ) |
|---|
| | 387 | { |
|---|
| | 388 | p_sys->i_fd_video = OpenVideoDev( p_demux, p_sys->psz_vdev ); |
|---|
| | 389 | } |
|---|
| | 390 | } |
|---|
| | 391 | |
|---|
| | 392 | /* Find audio device */ |
|---|
| | 393 | if( p_sys->i_fd_audio < 0 ) |
|---|
| | 394 | { |
|---|
| | 395 | if( !p_sys->psz_adev || !*p_sys->psz_adev ) |
|---|
| | 396 | { |
|---|
| | 397 | if( p_sys->psz_adev ) free( p_sys->psz_adev ); |
|---|
| | 398 | p_sys->psz_adev = var_CreateGetString( p_demux, "v4l2-adev" );; |
|---|
| | 399 | } |
|---|
| | 400 | |
|---|
| | 401 | if( p_sys->psz_adev && *p_sys->psz_adev && ProbeAudioDev( p_demux, p_sys->psz_adev ) ) |
|---|
| | 402 | { |
|---|
| | 403 | p_sys->i_fd_audio = OpenAudioDev( p_demux, p_sys->psz_adev ); |
|---|
| | 404 | } |
|---|
| | 405 | } |
|---|
| | 406 | |
|---|
| | 407 | if( p_sys->i_fd_video < 0 && p_sys->i_fd_audio < 0 ) |
|---|
| | 408 | { |
|---|
| | 409 | Close( p_this ); |
|---|
| | 410 | return VLC_EGENERIC; |
|---|
| | 411 | } |
|---|
| | 417 | * ParseMRL: parse the options contained in the MRL |
|---|
| | 418 | *****************************************************************************/ |
|---|
| | 419 | static void ParseMRL( demux_t *p_demux ) |
|---|
| | 420 | { |
|---|
| | 421 | demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| | 422 | |
|---|
| | 423 | char *psz_dup = strdup( p_demux->psz_path ); |
|---|
| | 424 | char *psz_parser = psz_dup; |
|---|
| | 425 | |
|---|
| | 426 | while( *psz_parser && *psz_parser != ':' ) |
|---|
| | 427 | { |
|---|
| | 428 | psz_parser++; |
|---|
| | 429 | } |
|---|
| | 430 | |
|---|
| | 431 | if( *psz_parser == ':' ) |
|---|
| | 432 | { |
|---|
| | 433 | /* read options */ |
|---|
| | 434 | for( ;; ) |
|---|
| | 435 | { |
|---|
| | 436 | *psz_parser++ = '\0'; |
|---|
| | 437 | |
|---|
| | 438 | if( !strncmp( psz_parser, "adev=", strlen( "adev=" ) ) ) |
|---|
| | 439 | { |
|---|
| | 440 | int i_len; |
|---|
| | 441 | |
|---|
| | 442 | psz_parser += strlen( "adev=" ); |
|---|
| | 443 | if( strchr( psz_parser, ':' ) ) |
|---|
| | 444 | { |
|---|
| | 445 | i_len = strchr( psz_parser, ':' ) - psz_parser; |
|---|
| | 446 | } |
|---|
| | 447 | else |
|---|
| | 448 | { |
|---|
| | 449 | i_len = strlen( psz_parser ); |
|---|
| | 450 | } |
|---|
| | 451 | |
|---|
| | 452 | p_sys->psz_adev = strndup( psz_parser, i_len ); |
|---|
| | 453 | |
|---|
| | 454 | psz_parser += i_len; |
|---|
| | 455 | } |
|---|
| | 456 | else if( !strncmp( psz_parser, "standard=", strlen( "standard=" ) ) ) |
|---|
| | 457 | { |
|---|
| | 458 | psz_parser += strlen( "standard=" ); |
|---|
| | 459 | if( !strncmp( psz_parser, "pal", strlen( "pal" ) ) ) |
|---|
| | 460 | { |
|---|
| | 461 | p_sys->i_selected_standard_id = V4L2_STD_PAL; |
|---|
| | 462 | psz_parser += strlen( "pal" ); |
|---|
| | 463 | } |
|---|
| | 464 | else if( !strncmp( psz_parser, "ntsc", strlen( "ntsc" ) ) ) |
|---|
| | 465 | { |
|---|
| | 466 | p_sys->i_selected_standard_id = V4L2_STD_NTSC; |
|---|
| | 467 | psz_parser += strlen( "ntsc" ); |
|---|
| | 468 | } |
|---|
| | 469 | else if( !strncmp( psz_parser, "secam", strlen( "secam" ) ) ) |
|---|
| | 470 | { |
|---|
| | 471 | p_sys->i_selected_standard_id = V4L2_STD_SECAM; |
|---|
| | 472 | psz_parser += strlen( "secam" ); |
|---|
| | 473 | } |
|---|
| | 474 | else if( !strncmp( psz_parser, "default", strlen( "default" ) ) ) |
|---|
| | 475 | { |
|---|
| | 476 | p_sys->i_selected_standard_id = V4L2_STD_UNKNOWN; |
|---|
| | 477 | psz_parser += strlen( "default" ); |
|---|
| | 478 | } |
|---|
| | 479 | else |
|---|
| | 480 | { |
|---|
| | 481 | p_sys->i_selected_standard_id = i_standards_list[strtol( psz_parser, &psz_parser, 0 )]; |
|---|
| | 482 | } |
|---|
| | 483 | } |
|---|
| | 484 | else if( !strncmp( psz_parser, "chroma=", strlen( "chroma=" ) ) ) |
|---|
| | 485 | { |
|---|
| | 486 | int i_len; |
|---|
| | 487 | |
|---|
| | 488 | psz_parser += strlen( "chroma=" ); |
|---|
| | 489 | if( strchr( psz_parser, ':' ) ) |
|---|
| | 490 | { |
|---|
| | 491 | i_len = strchr( psz_parser, ':' ) - psz_parser; |
|---|
| | 492 | } |
|---|
| | 493 | else |
|---|
| | 494 | { |
|---|
| | 495 | i_len = strlen( psz_parser ); |
|---|
| | 496 | } |
|---|
| | 497 | |
|---|
| | 498 | char* chroma = strndup( psz_parser, i_len ); |
|---|
| | 499 | p_sys->i_fourcc = GetChromaFromFourcc( chroma ); |
|---|
| | 500 | free( chroma ); |
|---|
| | 501 | |
|---|
| | 502 | psz_parser += i_len; |
|---|
| | 503 | } |
|---|
| | 504 | else if( !strncmp( psz_parser, "input=", strlen( "input=" ) ) ) |
|---|
| | 505 | { |
|---|
| | 506 | p_sys->i_selected_input = strtol( psz_parser + strlen( "input=" ), |
|---|
| | 507 | &psz_parser, 0 ); |
|---|
| | 508 | } |
|---|
| | 509 | else if( !strncmp( psz_parser, "fps=", strlen( "fps=" ) ) ) |
|---|
| | 510 | { |
|---|
| | 511 | p_sys->f_fps = strtof( psz_parser + strlen( "fps=" ), |
|---|
| | 512 | &psz_parser ); |
|---|
| | 513 | } |
|---|
| | 514 | else if( !strncmp( psz_parser, "io=", strlen( "io=" ) ) ) |
|---|
| | 515 | { |
|---|
| | 516 | psz_parser += strlen( "io=" ); |
|---|
| | 517 | if( !strncmp( psz_parser, "read", strlen( "read" ) ) ) |
|---|
| | 518 | { |
|---|
| | 519 | p_sys->io = IO_METHOD_READ; |
|---|
| | 520 | psz_parser += strlen( "read" ); |
|---|
| | 521 | } |
|---|
| | 522 | else if( !strncmp( psz_parser, "mmap", strlen( "mmap" ) ) ) |
|---|
| | 523 | { |
|---|
| | 524 | p_sys->io = IO_METHOD_MMAP; |
|---|
| | 525 | psz_parser += strlen( "mmap" ); |
|---|
| | 526 | } |
|---|
| | 527 | else if( !strncmp( psz_parser, "userptr", strlen( "userptr" ) ) ) |
|---|
| | 528 | { |
|---|
| | 529 | p_sys->io = IO_METHOD_USERPTR; |
|---|
| | 530 | psz_parser += strlen( "userptr" ); |
|---|
| | 531 | } |
|---|
| | 532 | else |
|---|
| | 533 | { |
|---|
| | 534 | p_sys->io = strtol( psz_parser, &psz_parser, 0 ); |
|---|
| | 535 | } |
|---|
| | 536 | } |
|---|
| | 537 | else if( !strncmp( psz_parser, "samplerate=", |
|---|
| | 538 | strlen( "samplerate=" ) ) ) |
|---|
| | 539 | { |
|---|
| | 540 | p_sys->i_sample_rate = |
|---|
| | 541 | strtol( psz_parser + strlen( "samplerate=" ), |
|---|
| | 542 | &psz_parser, 0 ); |
|---|
| | 543 | } |
|---|
| | 544 | else if( !strncmp( psz_parser, "stereo", strlen( "stereo" ) ) ) |
|---|
| | 545 | { |
|---|
| | 546 | psz_parser += strlen( "stereo" ); |
|---|
| | 547 | p_sys->b_stereo = VLC_TRUE; |
|---|
| | 548 | } |
|---|
| | 549 | else if( !strncmp( psz_parser, "mono", strlen( "mono" ) ) ) |
|---|
| | 550 | { |
|---|
| | 551 | psz_parser += strlen( "mono" ); |
|---|
| | 552 | p_sys->b_stereo = VLC_FALSE; |
|---|
| | 553 | } |
|---|
| | 554 | else if( !strncmp( psz_parser, "caching=", strlen( "caching=" ) ) ) |
|---|
| | 555 | { |
|---|
| | 556 | p_sys->i_pts = strtol( psz_parser + strlen( "caching=" ), |
|---|
| | 557 | &psz_parser, DEFAULT_PTS_DELAY / 1000 ); |
|---|
| | 558 | } |
|---|
| | 559 | else |
|---|
| | 560 | { |
|---|
| | 561 | msg_Warn( p_demux, "unknown option" ); |
|---|
| | 562 | } |
|---|
| | 563 | |
|---|
| | 564 | while( *psz_parser && *psz_parser != ':' ) |
|---|
| | 565 | { |
|---|
| | 566 | psz_parser++; |
|---|
| | 567 | } |
|---|
| | 568 | |
|---|
| | 569 | if( *psz_parser == '\0' ) |
|---|
| | 570 | { |
|---|
| | 571 | break; |
|---|
| | 572 | } |
|---|
| | 573 | } |
|---|
| | 574 | } |
|---|
| | 575 | |
|---|
| | 576 | /* Main device */ |
|---|
| | 577 | if( *psz_dup ) |
|---|
| | 578 | { |
|---|
| | 579 | p_sys->psz_device = strdup( psz_dup ); |
|---|
| | 580 | } |
|---|
| | 581 | if( psz_dup ) free( psz_dup ); |
|---|
| | 582 | } |
|---|
| | 583 | |
|---|
| | 584 | /***************************************************************************** |
|---|
| | 736 | /***************************************************************************** |
|---|
| | 737 | * GrabVideo: Grab a video frame |
|---|
| | 738 | *****************************************************************************/ |
|---|
| | 739 | static block_t* GrabVideo( demux_t *p_demux ) |
|---|
| | 740 | { |
|---|
| | 741 | demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| | 742 | |
|---|
| | 743 | block_t *p_block = NULL; |
|---|
| | 744 | struct v4l2_buffer buf; |
|---|
| | 745 | |
|---|
| | 746 | if( p_sys->f_fps >= 0.1 && p_sys->i_video_pts > 0 ) |
|---|
| | 747 | { |
|---|
| | 748 | mtime_t i_dur = (mtime_t)((double)1000000 / (double)p_sys->f_fps); |
|---|
| | 749 | |
|---|
| | 750 | /* Did we wait long enough ? (frame rate reduction) */ |
|---|
| | 751 | if( p_sys->i_video_pts + i_dur > mdate() ) return 0; |
|---|
| | 752 | } |
|---|
| | 753 | |
|---|
| | 754 | /* Grab Video Frame */ |
|---|
| | 755 | switch( p_sys->io ) |
|---|
| | 756 | { |
|---|
| | 757 | case IO_METHOD_READ: |
|---|
| | 758 | if( read( p_sys->i_fd_video, p_sys->p_buffers[0].start, p_sys->p_buffers[0].length ) ) |
|---|
| | 759 | { |
|---|
| | 760 | switch( errno ) |
|---|
| | 761 | { |
|---|
| | 762 | case EAGAIN: |
|---|
| | 763 | return 0; |
|---|
| | 764 | case EIO: |
|---|
| | 765 | /* Could ignore EIO, see spec. */ |
|---|
| | 766 | /* fall through */ |
|---|
| | 767 | default: |
|---|
| | 768 | msg_Err( p_demux, "Failed to read frame" ); |
|---|
| | 769 | return 0; |
|---|
| | 770 | } |
|---|
| | 771 | } |
|---|
| | 772 | |
|---|
| | 773 | p_block = ProcessVideoFrame( p_demux, (uint8_t*)p_sys->p_buffers[0].start ); |
|---|
| | 774 | if( !p_block ) return 0; |
|---|
| | 775 | |
|---|
| | 776 | break; |
|---|
| | 777 | |
|---|
| | 778 | case IO_METHOD_MMAP: |
|---|
| | 779 | memset( &buf, 0, sizeof(buf) ); |
|---|
| | 780 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
|---|
| | 781 | buf.memory = V4L2_MEMORY_MMAP; |
|---|
| | 782 | |
|---|
| | 783 | /* Wait for next frame */ |
|---|
| | 784 | if (ioctl( p_sys->i_fd_video, VIDIOC_DQBUF, &buf ) < 0 ) |
|---|
| | 785 | { |
|---|
| | 786 | switch( errno ) |
|---|
| | 787 | { |
|---|
| | 788 | case EAGAIN: |
|---|
| | 789 | return 0; |
|---|
| | 790 | case EIO: |
|---|
| | 791 | /* Could ignore EIO, see spec. */ |
|---|
| | 792 | /* fall through */ |
|---|
| | 793 | default: |
|---|
| | 794 | msg_Err( p_demux, "Failed to wait (VIDIOC_DQBUF)" ); |
|---|
| | 795 | return 0; |
|---|
| | 796 | } |
|---|
| | 797 | } |
|---|
| | 798 | |
|---|
| | 799 | if( buf.index >= p_sys->i_nbuffers ) { |
|---|
| | 800 | msg_Err( p_demux, "Failed capturing new frame as i>=nbuffers" ); |
|---|
| | 801 | return 0; |
|---|
| | 802 | } |
|---|
| | 803 | |
|---|
| | 804 | p_block = ProcessVideoFrame( p_demux, p_sys->p_buffers[buf.index].start ); |
|---|
| | 805 | if( !p_block ) return 0; |
|---|
| | 806 | |
|---|
| | 807 | /* Unlock */ |
|---|
| | 808 | if( ioctl( p_sys->i_fd_video, VIDIOC_QBUF, &buf ) < 0 ) |
|---|
| | 809 | { |
|---|
| | 810 | msg_Err (p_demux, "Failed to unlock (VIDIOC_QBUF)"); |
|---|
| | 811 | return 0; |
|---|
| | 812 | } |
|---|
| | 813 | |
|---|
| | 814 | break; |
|---|
| | 815 | |
|---|
| | 816 | case IO_METHOD_USERPTR: |
|---|
| | 817 | memset( &buf, 0, sizeof(buf) ); |
|---|
| | 818 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
|---|
| | 819 | buf.memory = V4L2_MEMORY_USERPTR; |
|---|
| | 820 | |
|---|
| | 821 | /* Wait for next frame */ |
|---|
| | 822 | if (ioctl( p_sys->i_fd_video, VIDIOC_DQBUF, &buf ) < 0 ) |
|---|
| | 823 | { |
|---|
| | 824 | switch( errno ) |
|---|
| | 825 | { |
|---|
| | 826 | case EAGAIN: |
|---|
| | 827 | return 0; |
|---|
| | 828 | case EIO: |
|---|
| | 829 | /* Could ignore EIO, see spec. */ |
|---|
| | 830 | /* fall through */ |
|---|
| | 831 | default: |
|---|
| | 832 | msg_Err( p_demux, "Failed to wait (VIDIOC_DQBUF)" ); |
|---|
| | 833 | return 0; |
|---|
| | 834 | } |
|---|
| | 835 | } |
|---|
| | 836 | |
|---|
| | 837 | /* Find frame? */ |
|---|
| | 838 | unsigned int i; |
|---|
| | 839 | for( i = 0; i < p_sys->i_nbuffers; i++ ) |
|---|
| | 840 | { |
|---|
| | 841 | if( buf.m.userptr == (unsigned long)p_sys->p_buffers[i].start && |
|---|
| | 842 | buf.length == p_sys->p_buffers[i].length ) break; |
|---|
| | 843 | } |
|---|
| | 844 | |
|---|
| | 845 | if( i >= p_sys->i_nbuffers ) { |
|---|
| | 846 | msg_Err( p_demux, "Failed capturing new frame as i>=nbuffers" ); |
|---|
| | 847 | return 0; |
|---|
| | 848 | } |
|---|
| | 849 | |
|---|
| | 850 | p_block = ProcessVideoFrame( p_demux, (uint8_t*)buf.m.userptr ); |
|---|
| | 851 | if( !p_block ) return 0; |
|---|
| | 852 | |
|---|
| | 853 | /* Unlock */ |
|---|
| | 854 | if( ioctl( p_sys->i_fd_video, VIDIOC_QBUF, &buf ) < 0 ) |
|---|
| | 855 | { |
|---|
| | 856 | msg_Err (p_demux, "Failed to unlock (VIDIOC_QBUF)"); |
|---|
| | 857 | return 0; |
|---|
| | 858 | } |
|---|
| | 859 | |
|---|
| | 860 | break; |
|---|
| | 861 | |
|---|
| | 862 | } |
|---|
| | 863 | |
|---|
| | 864 | /* Timestamp */ |
|---|
| | 865 | p_sys->i_video_pts = p_block->i_pts = p_block->i_dts = mdate(); |
|---|
| | 866 | |
|---|
| | 867 | return p_block; |
|---|
| | 868 | } |
|---|
| | 869 | |
|---|
| | 870 | /***************************************************************************** |
|---|
| | 871 | * ProcessVideoFrame: Helper function to take a buffer and copy it into |
|---|
| | 872 | * a new block |
|---|
| | 873 | *****************************************************************************/ |
|---|
| | 874 | static block_t* ProcessVideoFrame( demux_t *p_demux, uint8_t *p_frame ) |
|---|
| | 875 | { |
|---|
| | 876 | demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| | 877 | block_t *p_block; |
|---|
| | 878 | |
|---|
| | 879 | if( !p_frame ) return 0; |
|---|
| | 880 | |
|---|
| | 881 | /* New block */ |
|---|
| | 882 | if( !( p_block = block_New( p_demux, p_sys->i_video_frame_size ) ) ) |
|---|
| | 883 | { |
|---|
| | 884 | msg_Warn( p_demux, "Cannot get new block" ); |
|---|
| | 885 | return 0; |
|---|
| | 886 | } |
|---|
| | 887 | |
|---|
| | 888 | /* Copy frame */ |
|---|
| | 889 | memcpy( p_block->p_buffer, p_frame, p_sys->i_video_frame_size ); |
|---|
| | 890 | |
|---|
| | 891 | return p_block; |
|---|
| | 892 | } |
|---|
| | 893 | |
|---|
| | 894 | /***************************************************************************** |
|---|
| | 895 | * GrabAudio: Grab an audio frame |
|---|
| | 896 | *****************************************************************************/ |
|---|
| | 897 | static block_t* GrabAudio( demux_t *p_demux ) |
|---|
| | 898 | { |
|---|
| | 899 | demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| | 900 | struct audio_buf_info buf_info; |
|---|
| | 901 | int i_read, i_correct; |
|---|
| | 902 | block_t *p_block; |
|---|
| | 903 | |
|---|
| | 904 | /* Copied from v4l.c */ |
|---|
| | 905 | |
|---|
| | 906 | if( p_sys->p_block_audio ) p_block = p_sys->p_block_audio; |
|---|
| | 907 | else p_block = block_New( p_demux, p_sys->i_audio_max_frame_size ); |
|---|
| | 908 | |
|---|
| | 909 | if( !p_block ) |
|---|
| | 910 | { |
|---|
| | 911 | msg_Warn( p_demux, "cannot get block" ); |
|---|
| | 912 | return 0; |
|---|
| | 913 | } |
|---|
| | 914 | |
|---|
| | 915 | p_sys->p_block_audio = p_block; |
|---|
| | 916 | |
|---|
| | 917 | i_read = read( p_sys->i_fd_audio, p_block->p_buffer, |
|---|
| | 918 | p_sys->i_audio_max_frame_size ); |
|---|
| | 919 | |
|---|
| | 920 | if( i_read <= 0 ) return 0; |
|---|
| | 921 | |
|---|
| | 922 | p_block->i_buffer = i_read; |
|---|
| | 923 | p_sys->p_block_audio = 0; |
|---|
| | 924 | |
|---|
| | 925 | /* Correct the date because of kernel buffering */ |
|---|
| | 926 | i_correct = i_read; |
|---|
| | 927 | if( ioctl( p_sys->i_fd_audio, SNDCTL_DSP_GETISPACE, &buf_info ) == 0 ) |
|---|
| | 928 | { |
|---|
| | 929 | i_correct += buf_info.bytes; |
|---|
| | 930 | } |
|---|
| | 931 | |
|---|
| | 932 | /* Timestamp */ |
|---|
| | 933 | p_block->i_pts = p_block->i_dts = |
|---|
| | 934 | mdate() - I64C(1000000) * (mtime_t)i_correct / |
|---|
| | 935 | 2 / ( p_sys->b_stereo ? 2 : 1) / p_sys->i_sample_rate; |
|---|
| | 936 | |
|---|
| | 937 | return p_block; |
|---|
| | 938 | } |
|---|
| | 939 | |
|---|
| | 940 | /***************************************************************************** |
|---|
| | 941 | * Helper function to initalise video IO using the Read method |
|---|
| | 942 | *****************************************************************************/ |
|---|
| | 943 | static int InitRead( demux_t *p_demux, int i_fd, unsigned int i_buffer_size ) |
|---|
| | 944 | { |
|---|
| | 945 | demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| | 946 | |
|---|
| | 947 | p_sys->p_buffers = calloc( 1, sizeof( *p_sys->p_buffers ) ); |
|---|
| | 948 | if( !p_sys->p_buffers ) |
|---|
| | 949 | { |
|---|
| | 950 | msg_Err( p_demux, "Out of memory" ); |
|---|
| | 951 | goto open_failed; |
|---|
| | 952 | } |
|---|
| | 953 | |
|---|
| | 954 | p_sys->p_buffers[0].length = i_buffer_size; |
|---|
| | 955 | p_sys->p_buffers[0].start = malloc( i_buffer_size ); |
|---|
| | 956 | if( !p_sys->p_buffers[0].start ) |
|---|
| | 957 | { |
|---|
| | 958 | msg_Err( p_demux, "Out of memory" ); |
|---|
| | 959 | goto open_failed; |
|---|
| | 960 | } |
|---|
| | 961 | |
|---|
| | 962 | return VLC_SUCCESS; |
|---|
| | 963 | |
|---|
| | 964 | open_failed: |
|---|
| | 965 | return VLC_EGENERIC; |
|---|
| | 966 | |
|---|
| | 967 | } |
|---|
| | 968 | |
|---|
| | 969 | /***************************************************************************** |
|---|
| | 970 | * Helper function to initalise video IO using the mmap method |
|---|
| | 971 | *****************************************************************************/ |
|---|
| | 972 | static int InitMmap( demux_t *p_demux, int i_fd ) |
|---|
| | 973 | { |
|---|
| | 974 | demux_sys_t *p_sys = p_demux->p_sys; |
|---|
| | 975 | struct v4l2_requestbuffers req; |
|---|
| | 976 | |
|---|
| | 977 | memset( &req, 0, sizeof(req) ); |
|---|
| | 978 | req.count = 4; |
|---|
| | 979 | req.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
|---|
| | 980 | req.memory = V4L2_MEMORY_MMAP; |
|---|
| | 981 | |
|---|
| | 982 | if( ioctl( i_fd, VIDIOC_REQBUFS, &req ) < 0 ) |
|---|
| | 983 | { |
|---|
| | 984 | msg_Err( p_demux, "device does not support mmap i/o" ); |
|---|
| | 985 | goto open_failed; |
|---|
| | 986 | } |
|---|
| | 987 | |
|---|
| | 988 | if( req.count < 2 ) |
|---|
| | 989 | { |
|---|
| | 990 | msg_Err( p_demux, "Insufficient buffer memory" ); |
|---|
| | 991 | goto open_failed; |
|---|
| | 992 | } |
|---|
| | 993 | |
|---|
| | 994 | p_sys->p_buffers = calloc( req.count, sizeof( *p_sys->p_buffers ) ); |
|---|
| | 995 | if( !p_sys->p_buffers ) |
|---|
| | 996 | { |
|---|
| | 997 | msg_Err( p_demux, "Out of memory" ); |
|---|
| | 998 | goto open_failed; |
|---|
| | 999 | } |
|---|
| | 1000 | |
|---|
| | 1001 | for( p_sys->i_nbuffers = 0; p_sys->i_nbuffers < req.count; ++p_sys->i_nbuffers ) |
|---|
| | 1002 | { |
|---|
| | 1003 | struct v4l2_buffer buf; |
|---|
| | 1004 | |
|---|
| | 1005 | memset( &buf, 0, sizeof(buf) ); |
|---|
| | 1006 | buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE; |
|---|
| | 1007 | buf.memory = V4L2_MEMORY_MMAP; |
|---|
| | 1008 | buf.index = p_sys->i_nbuffers; |
|---|
| | 1009 | |
|---|
| | 1010 | if( ioctl( i_fd, VIDIOC_QUERYBUF, &buf ) < 0 ) |
|---|
| | 1011 | { |
|---|
| | 1012 | msg_Err( p_demux, "VIDIOC_QUERYBUF" ); |
|---|
| | 1013 | goto open_failed; |
|---|
| | 1014 | } |
|---|
| | 1015 | |
|---|
| | 1016 | p_sys->p_buffers[p_sys->i_nbuffers].length = buf.length; |
|---|
| | 1017 | p_sys->p_buffers[p_sys->i_nbuffers].start = |
|---|
| | 1018 | mmap( NULL, buf.length, PROT_READ | PROT_WRITE, MAP_SHARED, p_sys->i_fd_video, buf.m |
|---|