| 1 | /* |
|---|
| 2 | mediastreamer2 library - modular sound and video processing and streaming |
|---|
| 3 | Copyright (C) 2006 Simon MORLAT (simon.morlat@linphone.org) |
|---|
| 4 | |
|---|
| 5 | This program is free software; you can redistribute it and/or |
|---|
| 6 | modify it under the terms of the GNU General Public License |
|---|
| 7 | as published by the Free Software Foundation; either version 2 |
|---|
| 8 | of the License, or (at your option) any later version. |
|---|
| 9 | |
|---|
| 10 | This program is distributed in the hope that it will be useful, |
|---|
| 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
|---|
| 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
|---|
| 13 | GNU General Public License for more details. |
|---|
| 14 | |
|---|
| 15 | You should have received a copy of the GNU General Public License |
|---|
| 16 | along with this program; if not, write to the Free Software |
|---|
| 17 | Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. |
|---|
| 18 | */ |
|---|
| 19 | |
|---|
| 20 | #ifdef HAVE_CONFIG_H |
|---|
| 21 | #include "mediastreamer-config.h" |
|---|
| 22 | #endif |
|---|
| 23 | |
|---|
| 24 | #include "mediastreamer2/mscommon.h" |
|---|
| 25 | #include "mediastreamer2/msvideo.h" |
|---|
| 26 | #include "mediastreamer2/msfilter.h" |
|---|
| 27 | #include "mediastreamer2/msticker.h" |
|---|
| 28 | #include "mediastreamer2/mswebcam.h" |
|---|
| 29 | |
|---|
| 30 | #include "ffmpeg-priv.h" |
|---|
| 31 | |
|---|
| 32 | #include <sys/stat.h> |
|---|
| 33 | |
|---|
| 34 | #ifdef WIN32 |
|---|
| 35 | #include <fcntl.h> |
|---|
| 36 | #include <sys/types.h> |
|---|
| 37 | #include <io.h> |
|---|
| 38 | #include <stdio.h> |
|---|
| 39 | #include <malloc.h> |
|---|
| 40 | #endif |
|---|
| 41 | |
|---|
| 42 | static mblk_t *jpeg2yuv(uint8_t *jpgbuf, int bufsize, MSVideoSize *reqsize){ |
|---|
| 43 | AVCodecContext av_context; |
|---|
| 44 | int got_picture=0; |
|---|
| 45 | AVFrame orig; |
|---|
| 46 | AVPicture dest; |
|---|
| 47 | mblk_t *ret; |
|---|
| 48 | struct SwsContext *sws_ctx; |
|---|
| 49 | |
|---|
| 50 | avcodec_get_context_defaults(&av_context); |
|---|
| 51 | if (avcodec_open(&av_context,avcodec_find_decoder(CODEC_ID_MJPEG))<0){ |
|---|
| 52 | ms_error("jpeg2yuv: avcodec_open failed"); |
|---|
| 53 | return NULL; |
|---|
| 54 | } |
|---|
| 55 | if (avcodec_decode_video(&av_context,&orig,&got_picture,jpgbuf,bufsize)<0){ |
|---|
| 56 | ms_error("jpeg2yuv: avcodec_decode_video failed"); |
|---|
| 57 | avcodec_close(&av_context); |
|---|
| 58 | return NULL; |
|---|
| 59 | } |
|---|
| 60 | ret=allocb(avpicture_get_size(PIX_FMT_YUV420P,reqsize->width,reqsize->height),0); |
|---|
| 61 | ret->b_wptr=ret->b_datap->db_lim; |
|---|
| 62 | avpicture_fill(&dest,ret->b_rptr,PIX_FMT_YUV420P,reqsize->width,reqsize->height); |
|---|
| 63 | |
|---|
| 64 | sws_ctx=sws_getContext(av_context.width,av_context.height,PIX_FMT_YUV420P, |
|---|
| 65 | reqsize->width,reqsize->height,PIX_FMT_YUV420P,SWS_FAST_BILINEAR, |
|---|
| 66 | NULL, NULL, NULL); |
|---|
| 67 | if (sws_scale(sws_ctx,orig.data,orig.linesize,0,av_context.height,dest.data,dest.linesize)<0){ |
|---|
| 68 | ms_error("jpeg2yuv: sws_scale() failed."); |
|---|
| 69 | } |
|---|
| 70 | sws_freeContext(sws_ctx); |
|---|
| 71 | avcodec_close(&av_context); |
|---|
| 72 | return ret; |
|---|
| 73 | } |
|---|
| 74 | |
|---|
| 75 | mblk_t *ms_load_jpeg_as_yuv(const char *jpgpath, MSVideoSize *reqsize){ |
|---|
| 76 | mblk_t *m=NULL; |
|---|
| 77 | struct stat statbuf; |
|---|
| 78 | uint8_t *jpgbuf; |
|---|
| 79 | #if !defined(_MSC_VER) |
|---|
| 80 | int fd=open(jpgpath,O_RDONLY); |
|---|
| 81 | #else |
|---|
| 82 | int fd=_open(jpgpath,O_RDONLY); |
|---|
| 83 | #endif |
|---|
| 84 | if (fd!=-1){ |
|---|
| 85 | fstat(fd,&statbuf); |
|---|
| 86 | jpgbuf=(uint8_t*)alloca(statbuf.st_size); |
|---|
| 87 | #if !defined(_MSC_VER) |
|---|
| 88 | read(fd,jpgbuf,statbuf.st_size); |
|---|
| 89 | #else |
|---|
| 90 | _read(fd,jpgbuf,statbuf.st_size); |
|---|
| 91 | #endif |
|---|
| 92 | m=jpeg2yuv(jpgbuf,statbuf.st_size,reqsize); |
|---|
| 93 | }else{ |
|---|
| 94 | ms_error("Cannot load %s",jpgpath); |
|---|
| 95 | } |
|---|
| 96 | return m; |
|---|
| 97 | } |
|---|
| 98 | |
|---|
| 99 | #ifndef PACKAGE_DATA_DIR |
|---|
| 100 | #define PACKAGE_DATA_DIR "." |
|---|
| 101 | #endif |
|---|
| 102 | |
|---|
| 103 | #ifndef NOWEBCAM_JPG |
|---|
| 104 | #define NOWEBCAM_JPG "nowebcamCIF" |
|---|
| 105 | #endif |
|---|
| 106 | |
|---|
| 107 | mblk_t *ms_load_nowebcam(MSVideoSize *reqsize, int idx){ |
|---|
| 108 | char tmp[256]; |
|---|
| 109 | if (idx<0) |
|---|
| 110 | snprintf(tmp, sizeof(tmp), "%s/images/%s.jpg", PACKAGE_DATA_DIR, NOWEBCAM_JPG); |
|---|
| 111 | else |
|---|
| 112 | snprintf(tmp, sizeof(tmp), "%s/images/%s%i.jpg", PACKAGE_DATA_DIR, NOWEBCAM_JPG, idx); |
|---|
| 113 | return ms_load_jpeg_as_yuv(tmp,reqsize); |
|---|
| 114 | } |
|---|
| 115 | |
|---|
| 116 | typedef struct _SIData{ |
|---|
| 117 | MSVideoSize vsize; |
|---|
| 118 | char nowebcamimage[256]; |
|---|
| 119 | int index; |
|---|
| 120 | uint64_t lasttime; |
|---|
| 121 | mblk_t *pic; |
|---|
| 122 | }SIData; |
|---|
| 123 | |
|---|
| 124 | void static_image_init(MSFilter *f){ |
|---|
| 125 | SIData *d=(SIData*)ms_new(SIData,1); |
|---|
| 126 | d->vsize.width=MS_VIDEO_SIZE_CIF_W; |
|---|
| 127 | d->vsize.height=MS_VIDEO_SIZE_CIF_H; |
|---|
| 128 | memset(d->nowebcamimage, 0, sizeof(d->nowebcamimage)); |
|---|
| 129 | d->index=-1; |
|---|
| 130 | d->lasttime=0; |
|---|
| 131 | d->pic=NULL; |
|---|
| 132 | f->data=d; |
|---|
| 133 | } |
|---|
| 134 | |
|---|
| 135 | void static_image_uninit(MSFilter *f){ |
|---|
| 136 | ms_free(f->data); |
|---|
| 137 | } |
|---|
| 138 | |
|---|
| 139 | void static_image_preprocess(MSFilter *f){ |
|---|
| 140 | SIData *d=(SIData*)f->data; |
|---|
| 141 | if (d->pic==NULL){ |
|---|
| 142 | if (d->nowebcamimage[0] != '\0') |
|---|
| 143 | d->pic=ms_load_jpeg_as_yuv(d->nowebcamimage,&d->vsize); |
|---|
| 144 | else |
|---|
| 145 | d->pic=ms_load_nowebcam(&d->vsize,d->index); |
|---|
| 146 | } |
|---|
| 147 | } |
|---|
| 148 | |
|---|
| 149 | void static_image_process(MSFilter *f){ |
|---|
| 150 | SIData *d=(SIData*)f->data; |
|---|
| 151 | /*output a frame every second*/ |
|---|
| 152 | if ((f->ticker->time - d->lasttime>1000) || d->lasttime==0){ |
|---|
| 153 | ms_mutex_lock(&f->lock); |
|---|
| 154 | if (d->pic) { |
|---|
| 155 | mblk_t *o=dupb(d->pic); |
|---|
| 156 | /*prevent mirroring at the output*/ |
|---|
| 157 | mblk_set_precious_flag(o,1); |
|---|
| 158 | ms_queue_put(f->outputs[0],o); |
|---|
| 159 | } |
|---|
| 160 | ms_mutex_unlock(&f->lock); |
|---|
| 161 | d->lasttime=f->ticker->time; |
|---|
| 162 | } |
|---|
| 163 | } |
|---|
| 164 | |
|---|
| 165 | void static_image_postprocess(MSFilter *f){ |
|---|
| 166 | SIData *d=(SIData*)f->data; |
|---|
| 167 | if (d->pic) { |
|---|
| 168 | freemsg(d->pic); |
|---|
| 169 | d->pic=NULL; |
|---|
| 170 | } |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | int static_image_set_vsize(MSFilter *f, void* data){ |
|---|
| 174 | SIData *d=(SIData*)f->data; |
|---|
| 175 | d->vsize=*(MSVideoSize*)data; |
|---|
| 176 | return 0; |
|---|
| 177 | } |
|---|
| 178 | |
|---|
| 179 | int static_image_get_vsize(MSFilter *f, void* data){ |
|---|
| 180 | SIData *d=(SIData*)f->data; |
|---|
| 181 | *(MSVideoSize*)data=d->vsize; |
|---|
| 182 | return 0; |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | int static_image_get_pix_fmt(MSFilter *f, void *data){ |
|---|
| 186 | *(MSPixFmt*)data=MS_YUV420P; |
|---|
| 187 | return 0; |
|---|
| 188 | } |
|---|
| 189 | |
|---|
| 190 | static int static_image_set_image(MSFilter *f, void *arg){ |
|---|
| 191 | SIData *d=(SIData*)f->data; |
|---|
| 192 | char *image = (char *)arg; |
|---|
| 193 | ms_mutex_lock(&f->lock); |
|---|
| 194 | if (image!=NULL && image[0]!='\0') |
|---|
| 195 | snprintf(d->nowebcamimage, sizeof(d->nowebcamimage), "%s", image); |
|---|
| 196 | else |
|---|
| 197 | d->nowebcamimage[0] = '\0'; |
|---|
| 198 | |
|---|
| 199 | if (d->pic!=NULL) |
|---|
| 200 | freemsg(d->pic); |
|---|
| 201 | |
|---|
| 202 | //if (d->nowebcamimage[0] != '\0') |
|---|
| 203 | // d->pic=ms_load_jpeg_as_yuv(d->nowebcamimage,&d->vsize); |
|---|
| 204 | //else |
|---|
| 205 | // d->pic=ms_load_nowebcam(&d->vsize,d->index); |
|---|
| 206 | ms_mutex_unlock(&f->lock); |
|---|
| 207 | return 0; |
|---|
| 208 | } |
|---|
| 209 | |
|---|
| 210 | MSFilterMethod static_image_methods[]={ |
|---|
| 211 | { MS_FILTER_SET_VIDEO_SIZE, static_image_set_vsize }, |
|---|
| 212 | { MS_FILTER_GET_VIDEO_SIZE, static_image_get_vsize }, |
|---|
| 213 | { MS_FILTER_GET_PIX_FMT, static_image_get_pix_fmt }, |
|---|
| 214 | { MS_FILTER_SET_IMAGE, static_image_set_image }, |
|---|
| 215 | { 0,0 } |
|---|
| 216 | }; |
|---|
| 217 | |
|---|
| 218 | MSFilterDesc ms_static_image_desc={ |
|---|
| 219 | MS_STATIC_IMAGE_ID, |
|---|
| 220 | "MSStaticImage", |
|---|
| 221 | "A filter that outputs a static image.", |
|---|
| 222 | MS_FILTER_OTHER, |
|---|
| 223 | NULL, |
|---|
| 224 | 0, |
|---|
| 225 | 1, |
|---|
| 226 | static_image_init, |
|---|
| 227 | static_image_preprocess, |
|---|
| 228 | static_image_process, |
|---|
| 229 | static_image_postprocess, |
|---|
| 230 | static_image_uninit, |
|---|
| 231 | static_image_methods |
|---|
| 232 | }; |
|---|
| 233 | |
|---|
| 234 | MS_FILTER_DESC_EXPORT(ms_static_image_desc) |
|---|
| 235 | |
|---|
| 236 | static void static_image_detect(MSWebCamManager *obj); |
|---|
| 237 | |
|---|
| 238 | static void static_image_cam_init(MSWebCam *cam){ |
|---|
| 239 | cam->name=ms_strdup("Static picture"); |
|---|
| 240 | } |
|---|
| 241 | |
|---|
| 242 | |
|---|
| 243 | static MSFilter *static_image_create_reader(MSWebCam *obj){ |
|---|
| 244 | return ms_filter_new_from_desc(&ms_static_image_desc); |
|---|
| 245 | } |
|---|
| 246 | |
|---|
| 247 | MSWebCamDesc static_image_desc={ |
|---|
| 248 | "StaticImage", |
|---|
| 249 | &static_image_detect, |
|---|
| 250 | &static_image_cam_init, |
|---|
| 251 | &static_image_create_reader, |
|---|
| 252 | NULL |
|---|
| 253 | }; |
|---|
| 254 | |
|---|
| 255 | static void static_image_detect(MSWebCamManager *obj){ |
|---|
| 256 | MSWebCam *cam=ms_web_cam_new(&static_image_desc); |
|---|
| 257 | ms_web_cam_manager_add_cam(obj,cam); |
|---|
| 258 | } |
|---|
| 259 | |
|---|