Commit 9ab39114 authored by Simon Morlat's avatar Simon Morlat

implement jpegwriter to take snapshots of incoming video stream

parent 9492b114
......@@ -28,7 +28,8 @@ mediastreamer2_include_HEADERS= ice.h \
mschanadapter.h \
msaudiomixer.h \
msitc.h \
msextdisplay.h
msextdisplay.h \
msjpegwriter.h
EXTRA_DIST=$(mediastreamer2_include_HEADERS)
......@@ -101,7 +101,8 @@ typedef enum MSFilterId{
MS_IOUNIT_READ_ID,
MS_IOUNIT_WRITE_ID,
MS_ANDROID_SOUND_READ_ID,
MS_ANDROID_SOUND_WRITE_ID
MS_ANDROID_SOUND_WRITE_ID,
MS_JPEG_WRITER_ID
} MSFilterId;
......
......@@ -185,6 +185,8 @@ struct _VideoStream
MSFilter *decoder;
MSFilter *rtprecv;
MSFilter *rtpsend;
MSFilter *tee2;
MSFilter *jpegwriter;
OrtpEvQueue *evq;
MSVideoSize sent_vsize;
int corner; /*for selfview*/
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Belledonne Communications SARL (simon.morlat@linphone.org)
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
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#ifndef msjpegwriter_h
#define msjpegwriter_h
#include "mediastreamer2/msfilter.h"
#define MS_JPEG_WRITER_TAKE_SNAPSHOT MS_FILTER_METHOD(MS_JPEG_WRITER_ID,0,const char)
#endif
......@@ -127,7 +127,8 @@ libmediastreamer_la_SOURCES+= videoenc.c \
nowebcam.c nowebcam.h \
videoout.c \
swscale.h ffmpeg-priv.h \
h264dec.c
h264dec.c \
jpegwriter.c
endif
libmediastreamer_la_SOURCES+= rfc2429.h \
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2010 Belledonne Communications SARL <simon.morlat@linphone.org>
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
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mediastreamer2/msjpegwriter.h"
#include "mediastreamer2/msvideo.h"
#include "ffmpeg-priv.h"
typedef struct {
FILE *file;
AVCodec *codec;
}JpegWriter;
static void jpg_init(MSFilter *f){
JpegWriter *s=ms_new0(JpegWriter,1);
s->codec=avcodec_find_encoder(CODEC_ID_MJPEG);
if (s->codec==NULL){
ms_error("Could not find CODEC_ID_MJPEG !");
}
f->data=s;
}
static void jpg_uninit(MSFilter *f){
JpegWriter *s=(JpegWriter*)f->data;
if (s->file!=NULL){
fclose(s->file);
}
ms_free(s);
}
static int take_snapshot(MSFilter *f, void *arg){
JpegWriter *s=(JpegWriter*)f->data;
const char *filename=(const char*)arg;
if (s->file!=NULL){
fclose(s->file);
s->file=NULL;
}
s->file=fopen(filename,"w");
if (s->file==NULL){
ms_error("Could not open %s",filename);
return -1;
}
return 0;
}
static void jpg_process(MSFilter *f){
JpegWriter *s=(JpegWriter*)f->data;
if (s->file!=NULL && s->codec!=NULL){
MSPicture yuvbuf;
mblk_t *m=ms_queue_get(f->inputs[0]);
if (yuv_buf_init_from_mblk(&yuvbuf,m)==0){
int error;
int comp_buf_sz=msgdsize(m);
uint8_t *comp_buf=(uint8_t*)alloca(comp_buf_sz);
AVFrame pict;
AVCodecContext *avctx=avcodec_alloc_context();
avctx->width=yuvbuf.w;
avctx->height=yuvbuf.h;
avctx->pix_fmt=PIX_FMT_YUV420P;
error=avcodec_open(avctx,s->codec);
if (error!=0) {
ms_error("avcodec_open() failed: %i",error);
av_free(avctx);
return;
}
avcodec_get_frame_defaults(&pict);
avpicture_fill((AVPicture*)&pict,(uint8_t*)m->b_rptr,avctx->pix_fmt,avctx->width,avctx->height);
error=avcodec_encode_video(avctx, (uint8_t*)comp_buf,comp_buf_sz, &pict);
if (error<0){
ms_error("Could not encode jpeg picture.");
}else{
fwrite(comp_buf,error,1,s->file);
ms_message("Snapshot done");
}
fclose(s->file);
s->file=NULL;
avcodec_close(avctx);
av_free(avctx);
}
freemsg(m);
}
ms_queue_flush(f->inputs[0]);
}
static MSFilterMethod jpg_methods[]={
{ MS_JPEG_WRITER_TAKE_SNAPSHOT, take_snapshot },
{ 0,NULL}
};
#ifndef _MSC_VER
MSFilterDesc ms_jpeg_writer_desc={
.id=MS_JPEG_WRITER_ID,
.name="MSJpegWriter",
.category=MS_FILTER_OTHER,
.ninputs=1,
.noutputs=0,
.init=jpg_init,
.process=jpg_process,
.uninit=jpg_uninit,
.methods=jpg_methods
};
#else
MSFilterDesc ms_jpeg_writer_desc={
MS_JPEG_WRITER_ID,
"MSJpegWriter",
MS_FILTER_OTHER,
NULL,
1,
0,
pg_init,
NULL,
jpg_process,
NULL,
jpg_uninit,
jpg_methods
};
#endif
MS_FILTER_DESC_EXPORT(ms_jpeg_writer_desc)
......@@ -57,6 +57,10 @@ void video_stream_free (VideoStream * stream)
ms_filter_destroy(stream->pixconv);
if (stream->tee!=NULL)
ms_filter_destroy(stream->tee);
if (stream->tee2!=NULL)
ms_filter_destroy(stream->tee2);
if (stream->jpegwriter!=NULL)
ms_filter_destroy(stream->jpegwriter);
if (stream->ticker != NULL)
ms_ticker_destroy (stream->ticker);
if (stream->evq!=NULL)
......@@ -333,6 +337,7 @@ int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *re
ms_filter_link (stream->encoder,0, stream->rtpsend,0);
}
if (stream->dir==VideoStreamSendRecv || stream->dir==VideoStreamRecvOnly){
MSConnectionHelper ch;
/*plumb the incoming stream */
stream->decoder=ms_filter_create_decoder(pt->mime_type);
if ((stream->decoder==NULL) ){
......@@ -343,6 +348,9 @@ int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *re
stream->rtprecv = ms_filter_new (MS_RTP_RECV_ID);
ms_filter_call_method(stream->rtprecv,MS_RTP_RECV_SET_SESSION,stream->session);
stream->tee2=ms_filter_new(MS_TEE_ID);
stream->jpegwriter=ms_filter_new(MS_JPEG_WRITER_ID);
if (stream->rendercb!=NULL){
stream->output=ms_filter_new(MS_EXT_DISPLAY_ID);
ms_filter_set_notify_callback (stream->output,ext_display_cb,stream);
......@@ -370,8 +378,14 @@ int video_stream_start (VideoStream *stream, RtpProfile *profile, const char *re
ms_filter_call_method(stream->output,MS_VIDEO_DISPLAY_SET_LOCAL_VIEW_MODE,&stream->corner);
/* and connect the filters */
ms_filter_link (stream->rtprecv, 0, stream->decoder, 0);
ms_filter_link (stream->decoder,0 , stream->output, 0);
ms_connection_helper_start (&ch);
ms_connection_helper_link (&ch,stream->rtprecv,-1,0);
ms_connection_helper_link (&ch,stream->decoder,0,0);
if (stream->tee2){
ms_connection_helper_link (&ch,stream->tee2,0,0);
ms_filter_link(stream->tee2,1,stream->jpegwriter,0);
}
ms_connection_helper_link (&ch,stream->output,0,-1);
/* the video source must be send for preview , if it exists*/
if (stream->tee!=NULL)
ms_filter_link(stream->tee,1,stream->output,1);
......@@ -435,8 +449,15 @@ video_stream_stop (VideoStream * stream)
ms_filter_unlink(stream->encoder, 0, stream->rtpsend,0);
}
if (stream->rtprecv){
ms_filter_unlink(stream->rtprecv, 0, stream->decoder, 0);
ms_filter_unlink(stream->decoder,0,stream->output,0);
MSConnectionHelper h;
ms_connection_helper_start (&h);
ms_connection_helper_unlink (&h,stream->rtprecv,-1,0);
ms_connection_helper_unlink (&h,stream->decoder,0,0);
if (stream->tee2){
ms_connection_helper_unlink (&h,stream->tee2,0,0);
ms_filter_unlink(stream->tee2,1,stream->jpegwriter,0);
}
ms_connection_helper_unlink (&h,stream->output,0,-1);
if (stream->tee)
ms_filter_unlink(stream->tee,1,stream->output,1);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment