/* * Linux VeeJay * * Copyright(C)2002-2004 Niels Elburg * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License , or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software */ #include #include #include #include #include #include #include #include #include #include /* see vj-v4lvideo for details about structure */ #include #include typedef struct { y4m_stream_info_t streaminfo; y4m_frame_info_t frameinfo; y4m_ratio_t sar; y4m_ratio_t dar; int width; int height; int fd; float video_fps; int sar_w; int sar_h; } vj_yuv; int bytecount = 0; void *vj_yuv4mpeg_alloc(float fps, int w, int h, int sar_w, int sar_h) { vj_yuv *yuv4mpeg = (void *) vj_malloc(sizeof(vj_yuv)); if(!yuv4mpeg) return NULL; yuv4mpeg->sar = y4m_sar_UNKNOWN; yuv4mpeg->dar = y4m_dar_4_3; y4m_init_stream_info(&(yuv4mpeg->streaminfo)); y4m_init_frame_info(&(yuv4mpeg->frameinfo)); yuv4mpeg->width = w; yuv4mpeg->height = h; yuv4mpeg->video_fps = fps; yuv4mpeg->sar_w = sar_w; yuv4mpeg->sar_h = sar_h; return (void*)yuv4mpeg; } void vj_yuv4mpeg_free(void *v) { } int vj_yuv_stream_start_read(void *data, char *filename, int width, int height) { int i, w, h; vj_yuv *yuv4mpeg = (vj_yuv*) data; yuv4mpeg->fd = open(filename,O_RDONLY); if (!yuv4mpeg->fd) { veejay_msg(VEEJAY_MSG_ERROR, "Unable to open video stream %s\n", filename); return -1; } i = y4m_read_stream_header(yuv4mpeg->fd, &(yuv4mpeg->streaminfo)); if (i != Y4M_OK) { veejay_msg(VEEJAY_MSG_ERROR, "yuv4mpeg: %s", y4m_strerr(i)); return -1; } w = y4m_si_get_width(&(yuv4mpeg->streaminfo)); h = y4m_si_get_height(&(yuv4mpeg->streaminfo)); if( w != width || h != height ) { veejay_msg(VEEJAY_MSG_ERROR, "Video dimensions: %d x %d must match %d x %d. Stream cannot be opened", w, h, width, height); return -1; } veejay_msg(VEEJAY_MSG_DEBUG, "YUV4MPEG: stream header ok"); return 0; } int vj_yuv_stream_write_header(void * data) { vj_yuv *yuv4mpeg = (vj_yuv*) data; int i = 0; y4m_si_set_width(&(yuv4mpeg->streaminfo), yuv4mpeg->width); y4m_si_set_height(&(yuv4mpeg->streaminfo), yuv4mpeg->height); y4m_si_set_interlace(&(yuv4mpeg->streaminfo), 0); y4m_si_set_framerate(&(yuv4mpeg->streaminfo), mpeg_conform_framerate(yuv4mpeg->video_fps)); if (!Y4M_RATIO_EQL(yuv4mpeg->sar, y4m_sar_UNKNOWN)) { y4m_si_set_sampleaspect(&(yuv4mpeg->streaminfo), yuv4mpeg->sar); yuv4mpeg->sar.n = yuv4mpeg->sar_w; yuv4mpeg->sar.d = yuv4mpeg->sar_h; y4m_si_set_sampleaspect(&(yuv4mpeg->streaminfo), yuv4mpeg->sar); } else { y4m_ratio_t dar2 = y4m_guess_sar(yuv4mpeg->width, yuv4mpeg->height, yuv4mpeg->dar); y4m_si_set_sampleaspect(&(yuv4mpeg->streaminfo), dar2); } i = y4m_write_stream_header(yuv4mpeg->fd, &(yuv4mpeg->streaminfo)); if (i != Y4M_OK) return -1; y4m_log_stream_info(LOG_INFO, "vj-yuv4mpeg", &(yuv4mpeg->streaminfo)); return 0; } int vj_yuv_stream_open_pipe(void *data, char *filename) { vj_yuv *yuv4mpeg = (vj_yuv*) data; yuv4mpeg->fd = open(filename,O_WRONLY,0600); if(!yuv4mpeg->fd) return 0; return 1; } int vj_yuv_stream_header_pipe(void *data) { vj_yuv *yuv4mpeg = (vj_yuv*) data; vj_yuv_stream_write_header(yuv4mpeg); return 1; } int vj_yuv_stream_start_write(void *data, char *filename) { vj_yuv *yuv4mpeg = (vj_yuv*) data; struct stat sstat; if(strncasecmp( filename, "stdout", 6) == 0) { yuv4mpeg->fd = 1; } else { if(strncasecmp(filename, "stderr", 6) == 0) { yuv4mpeg->fd = 2; } else { if (stat(filename, &sstat) == 0) { if (S_ISREG(sstat.st_mode)) { /* the file is a regular file */ yuv4mpeg->fd = open(filename, O_APPEND | O_WRONLY, 0600); if (!yuv4mpeg->fd) return -1; } else { if (S_ISFIFO(sstat.st_mode)) veejay_msg(VEEJAY_MSG_INFO, "Destination file is a FIFO"); return 1; // pipe needs handling } } else { veejay_msg(VEEJAY_MSG_INFO, "Creating YUV4MPEG regular file %s\n", filename); yuv4mpeg->fd = open(filename, O_CREAT | O_WRONLY, 0600); if (!yuv4mpeg->fd) return -1; } } } vj_yuv_stream_write_header(yuv4mpeg); return 0; } void vj_yuv_stream_stop_write(void *data) { vj_yuv *yuv4mpeg = (vj_yuv*) data; y4m_fini_stream_info(&(yuv4mpeg->streaminfo)); y4m_fini_frame_info(&(yuv4mpeg->frameinfo)); close(yuv4mpeg->fd); } void vj_yuv_stream_stop_read(void *data) { vj_yuv *yuv4mpeg = (vj_yuv*) data; y4m_fini_stream_info(&(yuv4mpeg->streaminfo)); y4m_fini_frame_info(&(yuv4mpeg->frameinfo)); close(yuv4mpeg->fd); yuv4mpeg->sar = y4m_sar_UNKNOWN; yuv4mpeg->dar = y4m_dar_4_3; } int vj_yuv_get_frame(void *data, uint8_t * dst[3]) { int i; vj_yuv *yuv4mpeg = (vj_yuv*) data; i = y4m_read_frame(yuv4mpeg->fd, &(yuv4mpeg->streaminfo), &(yuv4mpeg->frameinfo), dst); if (i != Y4M_OK) { veejay_msg(VEEJAY_MSG_ERROR, "yuv4mpeg %s", y4m_strerr(i)); return -1; } return 0; } int vj_yuv_put_frame(void *data, uint8_t ** src) { vj_yuv *yuv4mpeg = (vj_yuv*) data; int i; if (!yuv4mpeg->fd) { veejay_msg(VEEJAY_MSG_ERROR, "Invalid file descriptor for y4m stream"); return -1; } i = y4m_write_frame(yuv4mpeg->fd, &(yuv4mpeg->streaminfo), &(yuv4mpeg->frameinfo), src); if (i != Y4M_OK) { veejay_msg(VEEJAY_MSG_ERROR, "Yuv4Mpeg : [%s]", y4m_strerr(i)); return -1; } return 0; }