Commit 364f3eca authored by Erwan Croze's avatar Erwan Croze 👋🏻

Adding turbojpeg a new jpeg dec/enc

parent 44348f4c
......@@ -90,6 +90,7 @@ option(ENABLE_BV16 "Build mediastreamer2 with the BV16 codec." YES)
option(ENABLE_OPUS "Build mediastreamer2 with the OPUS codec." YES)
option(ENABLE_SPEEX_CODEC "Build mediastreamer2 with the SPEEX codec." YES)
option(ENABLE_SPEEX_DSP "Build mediastreamer2 with the SPEEX DSP support." YES)
option(ENABLE_G729B_CNG "Build mediastremer2 with G729 annex B cng." NO)
cmake_dependent_option(ENABLE_RESAMPLE "Build mediastreamer2 with the resampling capability." YES "ENABLE_SPEEX_DSP" NO)
option(ENABLE_VIDEO "Build mediastreamer2 with video support." YES)
......@@ -104,7 +105,7 @@ cmake_dependent_option(ENABLE_VPX "Build mediastreamer2 with VPX codec." YES "EN
option(ENABLE_MKV "Enable support of MKV files reading and writing." YES)
cmake_dependent_option(ENABLE_QNX "Build medistreamer2 with BB10 filters." NO "ENABLE_VIDEO" NO)
cmake_dependent_option(ENABLE_VT_H264 "Build mediastreamer2 with H264 encoder/decoder based on VirtualToolbox (Apple only)" YES "ENABLE_VIDEO" NO)
option(ENABLE_G729B_CNG "Build mediastremer2 with G729 annex B cng." NO)
option(ENABLE_JPEG "Enable JPEG support" YES)
macro(apply_compile_flags SOURCE_FILES)
if(${SOURCE_FILES})
......@@ -324,6 +325,14 @@ if(ENABLE_G729B_CNG)
endif()
endif()
if(ENABLE_JPEG)
find_package(TurboJpeg)
if(NOT TURBOJPEG_FOUND)
message(WARNING "Could not find libturbo-jpeg, mediastreamer2 will be compiled without LibJpeg-Turbo")
set(ENABLE_JPEG OFF CACHE BOOL "Enable JPEG support" FORCE)
endif()
endif()
if(LINPHONE_BUILDER_GROUP_EXTERNAL_SOURCE_PATH_BUILDERS)
set(BcToolbox_FIND_COMPONENTS tester)
include("${EP_bctoolbox_CONFIG_DIR}/BcToolboxConfig.cmake")
......@@ -414,6 +423,9 @@ endif()
if(MSVC_INCLUDE_DIR)
include_directories(${MSVC_INCLUDE_DIR})
endif()
if(TURBOJPEG_FOUND)
include_directories(${TURBOJPEG_INCLUDE_DIRS})
endif()
if(ENABLE_ANDROIDSND)
include_directories(
src/android
......@@ -471,6 +483,9 @@ endif()
if(MATROSKA2_FOUND)
set(HAVE_MATROSKA 1)
endif()
if(TURBO_JPEG_FOUND)
set(HAVE_TURBO_JPEG 1)
endif()
if(ENABLE_RELATIVE_PREFIX)
if(CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" OR CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
set(PACKAGE_PLUGINS_DIR ".")
......@@ -593,5 +608,3 @@ install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/Mediastreamer2ConfigVersion.cmake"
DESTINATION ${CONFIG_PACKAGE_LOCATION}
)
############################################################################
# FindTurboJpeg.txt
# Copyright (C) 2016 Belledonne Communications, Grenoble France
#
############################################################################
#
# 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
############################################################################
#
# - Find the turbojpeg include file and library
#
# TURBOJPEG_FOUND - system has turbojpeg
# TURBOJPEG_INCLUDE_DIRS - the turbojpeg include directory
# TURBOJPEG_LIBRARIES - The libraries needed to use turbojpeg
find_path(TURBOJPEG_INCLUDE_DIRS
NAMES turbojpeg.h
PATH_SUFFIXES include
)
if(TURBOJPEG_INCLUDE_DIRS)
set(HAVE_TURBOJPEG_H 1)
endif()
find_library(TURBOJPEG_LIBRARIES
NAMES turbojpeg
)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(TurboJpeg
DEFAULT_MSG
TURBOJPEG_INCLUDE_DIRS TURBOJPEG_LIBRARIES
)
mark_as_advanced(TURBOJPEG_INCLUDE_DIRS TURBOJPEG_LIBRARIES)
......@@ -283,6 +283,15 @@ if(ENABLE_VIDEO)
voip/videostream.c
voip/video_preset_high_fps.c
)
if(FFMPEG_FOUND AND NOT TURBOJPEG_FOUND)
list(APPEND VOIP_SOURCE_FILES_C
videofilters/ffmpegnowebcam.c
)
elseif(TURBOJPEG_FOUND)
list(APPEND VOIP_SOURCE_FILES_C
videofilters/turbojpegnowebcam.c
)
endif()
if(WIN32 AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsPhone" AND NOT CMAKE_SYSTEM_NAME STREQUAL "WindowsStore")
add_definitions(-DHAVE_DIRECTSHOW)
list(APPEND VOIP_SOURCE_FILES_C
......@@ -311,7 +320,7 @@ if(ENABLE_VIDEO)
videofilters/msosxdisplay.m
videofilters/avfound-capture.m
)
list(APPEND VOIP_SOURCE_FILES_C
utils/opengles_display.c
utils/opengles_display.h
......@@ -358,10 +367,19 @@ if(ENABLE_VIDEO)
utils/ffmpeg-priv.h
utils/swscale.h
videofilters/h264dec.c
videofilters/jpegwriter.c
videofilters/videodec.c
videofilters/videoenc.c
)
if(NOT TURBOJPEG_FOUND)
list(APPEND VOIP_SOURCE_FILES_C
videofilters/ffmpegjpegwriter.c
)
endif()
endif()
if(TURBOJPEG_FOUND)
list(APPEND VOIP_SOURCE_FILES_C
videofilters/turbojpegwriter.c
)
endif()
if(GLX_FOUND)
list(APPEND VOIP_SOURCE_FILES_C
......@@ -577,6 +595,9 @@ endif()
if (CAMAPI_FOUND)
list(APPEND VOIP_LIBS ${CAMAPI_LIBRARIES})
endif()
if(TURBOJPEG_FOUND)
list(APPEND VOIP_LIBS ${TURBOJPEG_LIBRARIES})
endif()
if (BCGG729_FOUND)
add_definitions(-DHAVE_G729B=1)
list(APPEND VOIP_LIBS ${BCG729_LIBRARIES})
......@@ -632,12 +653,17 @@ endif()
if(FFMPEG_FOUND AND NOT WIN32)
set(NO_DEPRECATED_DECLARATIONS_SOURCE_FILES
videofilters/jpegwriter.c
videofilters/videoenc.c
videofilters/videodec.c
videofilters/nowebcam.c
videofilters/h264dec.c
)
if(NOT TURBOJPEG_FOUND)
set(NO_DEPRECATED_DECLARATIONS_SOURCE_FILES
${NO_DEPRECATED_DECLARATIONS_SOURCE_FILES}
videofilters/ffmpegjpegwriter.c
videofilters/nowebcam.c
)
endif()
foreach(file ${NO_DEPRECATED_DECLARATIONS_SOURCE_FILES})
get_source_file_property(NO_DEPRECATED_DECLARATIONS_COMPILE_FLAGS ${file} COMPILE_FLAGS)
set_source_files_properties(${file} PROPERTIES COMPILE_FLAGS "${NO_DEPRECATED_DECLARATIONS_COMPILE_FLAGS} -Wno-error=deprecated-declarations")
......
......@@ -63,7 +63,7 @@ typedef struct AVPacket{
}AVPacket;
static inline void av_init_packet(AVPacket *pkt){
}
static inline int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
int *got_picture_ptr,
......@@ -71,7 +71,7 @@ static inline int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
return avcodec_decode_video(avctx,picture, got_picture_ptr,avpkt->data,avpkt->size);
}
#endif
#if HAVE_AVCODEC_OLD_CODEC_IDS
#if HAVE_AVCODEC_OLD_CODEC_IDS
#include <libavcodec/old_codec_ids.h>
#endif
......@@ -90,15 +90,15 @@ static inline int avcodec_decode_video2(AVCodecContext *avctx, AVFrame *picture,
#endif
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,25,0)
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(54,25,0)
/*CODEC_ID_* and CodecID have been deprecated for a long time and this release removes it altogether. Please use AV_CODEC_ID_* and AVCodecID instead.*/
#define CodecID AVCodecID
#ifndef HAVE_AVCODEC_OLD_CODEC_IDS
#define CODEC_ID_H264 AV_CODEC_ID_H264
#define CODEC_ID_H263 AV_CODEC_ID_H263
#define CODEC_ID_H263P AV_CODEC_ID_H263P
#define CODEC_ID_MPEG4 AV_CODEC_ID_MPEG4
#define CODEC_ID_MJPEG AV_CODEC_ID_MJPEG
#define CODEC_ID_H264 AV_CODEC_ID_H264
#define CODEC_ID_H263 AV_CODEC_ID_H263
#define CODEC_ID_H263P AV_CODEC_ID_H263P
#define CODEC_ID_MPEG4 AV_CODEC_ID_MPEG4
#define CODEC_ID_MJPEG AV_CODEC_ID_MJPEG
#endif
#endif
......
......@@ -72,7 +72,7 @@ static void close_file(JpegWriter *obj, bool_t doRenaming) {
}
ms_free(obj->filename);
obj->filename = NULL;
ms_free(obj->tmpFilename);
obj->tmpFilename = NULL;
}
......
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2006 Simon MORLAT (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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif
#include "mediastreamer2/msvideo.h"
#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#ifndef NO_FFMPEG
#include "ffmpeg-priv.h"
#else
#define FF_INPUT_BUFFER_PADDING_SIZE 32
#endif
#if LIBAVCODEC_VERSION_MAJOR >= 57
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#endif
#if TARGET_OS_IPHONE
#include <CoreGraphics/CGDataProvider.h>
#include <CoreGraphics/CGImage.h>
#include <CoreGraphics/CGContext.h>
#include <CoreGraphics/CGBitmapContext.h>
#endif
#ifdef _WIN32
#include <fcntl.h>
#include <sys/types.h>
#include <io.h>
#include <stdio.h>
#include <malloc.h>
#endif
mblk_t *jpeg2yuv(uint8_t *jpgbuf, int bufsize, MSVideoSize *reqsize){
#if !defined(NO_FFMPEG) && !TARGET_OS_IPHONE /* this code must never be used for iOS */
AVCodecContext av_context;
int got_picture=0;
mblk_t *ret;
struct SwsContext *sws_ctx;
AVPacket pkt;
MSPicture dest;
AVCodec *codec=avcodec_find_decoder(CODEC_ID_MJPEG);
AVFrame* orig = av_frame_alloc();
if (codec==NULL){
ms_error("Could not find MJPEG decoder in ffmpeg.");
return NULL;
}
avcodec_get_context_defaults3(&av_context,NULL);
if (avcodec_open2(&av_context,codec,NULL)<0){
ms_error("jpeg2yuv: avcodec_open failed");
return NULL;
}
av_init_packet(&pkt);
pkt.data=jpgbuf;
pkt.size=bufsize;
if (avcodec_decode_video2(&av_context,orig,&got_picture,&pkt) < 0) {
ms_error("jpeg2yuv: avcodec_decode_video failed");
avcodec_close(&av_context);
return NULL;
}
ret=ms_yuv_buf_alloc(&dest, reqsize->width,reqsize->height);
/* not using SWS_FAST_BILINEAR because it doesn't play well with
* av_context.pix_fmt set to AV_PIX_FMT_YUVJ420P by jpeg decoder */
sws_ctx=sws_getContext(av_context.width,av_context.height,av_context.pix_fmt,
reqsize->width,reqsize->height,AV_PIX_FMT_YUV420P,SWS_BILINEAR,
NULL, NULL, NULL);
if (sws_ctx==NULL) {
ms_error("jpeg2yuv: ms_sws_getContext() failed.");
avcodec_close(&av_context);
freemsg(ret);
return NULL;
}
#if LIBSWSCALE_VERSION_INT >= AV_VERSION_INT(0,9,0)
if (sws_scale(sws_ctx,(const uint8_t* const *)orig->data,orig->linesize,0,av_context.height,dest.planes,dest.strides)<0){
#else
if (sws_scale(sws_ctx,(uint8_t**)orig->data,orig->linesize,0,av_context.height,dest.planes,dest.strides)<0){
#endif
ms_error("jpeg2yuv: ms_sws_scale() failed.");
sws_freeContext(sws_ctx);
avcodec_close(&av_context);
freemsg(ret);
return NULL;
}
sws_freeContext(sws_ctx);
av_frame_free(&orig);
avcodec_close(&av_context);
return ret;
#elif TARGET_OS_IPHONE
MSPicture dest;
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, jpgbuf, bufsize, NULL);
// use the data provider to get a CGImage; release the data provider
CGImageRef image = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, FALSE,
kCGRenderingIntentDefault);
CGDataProviderRelease(dataProvider);
reqsize->width = CGImageGetWidth(image);
reqsize->height = CGImageGetHeight(image);
uint8_t* tmp = (uint8_t*) malloc(reqsize->width * reqsize->height * 4);
mblk_t* ret=ms_yuv_buf_alloc(&dest, reqsize->width, reqsize->height);
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef imageContext =
CGBitmapContextCreate(tmp, reqsize->width, reqsize->height, 8, reqsize->width*4, colourSpace, kCGImageAlphaNoneSkipLast);
CGColorSpaceRelease(colourSpace);
// draw the image to the context, release it
CGContextDrawImage(imageContext, CGRectMake(0, 0, reqsize->width, reqsize->height), image);
CGImageRelease(image);
/* convert tmp/RGB -> ret/YUV */
for(int y=0; y<reqsize->height; y++) {
for(int x=0; x<reqsize->width; x++) {
uint8_t r = tmp[y * reqsize->width * 4 + x * 4 + 0];
uint8_t g = tmp[y * reqsize->width * 4 + x * 4 + 1];
uint8_t b = tmp[y * reqsize->width * 4 + x * 4 + 2];
// Y
*dest.planes[0]++ = (uint8_t)((0.257 * r) + (0.504 * g) + (0.098 * b) + 16);
// U/V subsampling
if ((y % 2==0) && (x%2==0)) {
uint32_t r32=0, g32=0, b32=0;
for(int i=0; i<2; i++) {
for(int j=0; j<2; j++) {
r32 += tmp[(y+i) * reqsize->width * 4 + (x+j) * 4 + 0];
g32 += tmp[(y+i) * reqsize->width * 4 + (x+j) * 4 + 1];
b32 += tmp[(y+i) * reqsize->width * 4 + (x+j) * 4 + 2];
}
}
r32 = (uint32_t)(r32 * 0.25f); g32 = (uint32_t)(g32 * 0.25f); b32 = (uint32_t) (b32 * 0.25f);
// U
*dest.planes[1]++ = (uint8_t)(-(0.148 * r32) - (0.291 * g32) + (0.439 * b32) + 128);
// V
*dest.planes[2]++ = (uint8_t)((0.439 * r32) - (0.368 * g32) - (0.071 * b32) + 128);
}
}
}
free(tmp);
return ret;
#else
return NULL;
#endif
}
#if __clang__
#pragma clang diagnostic pop
#endif
This diff is collapsed.
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2016 Belledonne Communications
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif
#include "mediastreamer2/msvideo.h"
#if __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
#endif
#include "turbojpeg.h"
#ifdef _MSC_VER
#pragma warning(disable : 4996)
#else
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#endif
#include <math.h>
mblk_t *jpeg2yuv(uint8_t *jpgbuf, int bufsize, MSVideoSize *reqsize) {
MSPicture dest;
mblk_t *m = NULL;
int imgsrch, imgsrcw, imgsrcsubsamp, imgsrccolor;
int scaledw, scaledh, sfnum;
tjscalingfactor* sf = NULL;
tjhandle turbojpegDec = tjInitDecompress();
if (turbojpegDec == NULL) {
ms_error("tjInitDecompress error: %s", tjGetErrorStr());
return NULL;
}
if (tjDecompressHeader3(
turbojpegDec,
jpgbuf,
bufsize,
&imgsrcw,
&imgsrch,
&imgsrcsubsamp,
&imgsrccolor
) != 0) {
ms_error("tjDecompressHeader3() failed, error: %s", tjGetErrorStr());
}
sf = tjGetScalingFactors(&sfnum);
// Prevision of height and width
for(int i = 0; i < sfnum; i++) {
scaledw = TJSCALED(imgsrcw, sf[i]);
scaledh = TJSCALED(imgsrch, sf[i]);
if (scaledw <= reqsize->width && scaledh <= reqsize->height)
break;
}
m = ms_yuv_buf_alloc(&dest, scaledw, scaledh);
if (m == NULL) goto clean;
if (tjDecompressToYUVPlanes(
turbojpegDec,
jpgbuf,
bufsize,
dest.planes,
dest.w,
dest.strides,
dest.h,
0
) != 0) {
ms_error("tjDecompressToYUVPlanes() failed, error: %s", tjGetErrorStr());
goto clean;
}
reqsize->width = scaledw;
reqsize->height = scaledh;
clean:
if (turbojpegDec != NULL) {
if (tjDestroy(turbojpegDec) != 0)
ms_error("tjDestroy decompress error: %s", tjGetErrorStr());
}
return m;
}
#if __clang__
#pragma clang diagnostic pop
#endif
/*
mediastreamer2 library - modular sound and video processing and streaming
Copyright (C) 2016 Belledonne Communications
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifdef HAVE_CONFIG_H
#include "mediastreamer-config.h"
#endif
#include "mediastreamer2/msjpegwriter.h"
#include "mediastreamer2/msvideo.h"
#include "turbojpeg.h"
typedef struct {
FILE *file;
char *filename;
char *tmpFilename;
tjhandle *turboJpeg;
MSFilter *f;
}JpegWriter;
static void close_file(JpegWriter *obj, bool_t doRenaming);
static bool_t open_file(JpegWriter *obj, const char *filename) {
obj->filename = ms_strdup(filename);
obj->tmpFilename = ms_strdup_printf("%s.part",filename);
obj->file = fopen(obj->tmpFilename, "wb");
if (!obj->file) {
ms_error("Could not open %s for write", obj->tmpFilename);
close_file(obj,FALSE);
}
return TRUE;
}
static void close_file(JpegWriter *obj, bool_t doRenaming) {
if (obj->file) {
fclose(obj->file);
obj->file = NULL;
}
if (doRenaming) {
if (rename(obj->tmpFilename, obj->filename) != 0) {
ms_error("Could not rename %s into %s", obj->tmpFilename, obj->filename);
} else {
ms_filter_notify(obj->f, MS_JPEG_WRITER_SNAPSHOT_TAKEN, (void *)obj->filename);
}
}
ms_free(obj->filename);
obj->filename = NULL;
ms_free(obj->tmpFilename);
obj->tmpFilename = NULL;
}
static void jpg_init(MSFilter *f) {
JpegWriter *s=ms_new0(JpegWriter,1);
s->f = f;
s->turboJpeg = tjInitCompress();
if (s->turboJpeg == NULL) {
ms_error("TurboJpeg init error:%s", tjGetErrorStr());
}
f->data=s;
}
static void jpg_uninit(MSFilter *f) {
JpegWriter *s = (JpegWriter*)f->data;
s->f = NULL;
if (s->file != NULL) {
close_file(s, FALSE);
}
if (s->turboJpeg != NULL) {
if (tjDestroy(s->turboJpeg) != 0)
ms_error("TurboJpeg destroy error:%s", tjGetErrorStr());
}
ms_free(s);
}
static int take_snapshot(MSFilter *f, void *arg) {
JpegWriter *s=(JpegWriter*)f->data;
const char *filename = (const char *)arg;
int err = 0;
ms_filter_lock(f);
if (s->file != NULL) {
close_file(s, FALSE);
}
if (!open_file(s, filename)) err=-1;
ms_filter_unlock(f);
return err;
}
static void cleanup(JpegWriter *s, bool_t success) {
if (s->file){
close_file(s, success);
}
}
static void jpg_process(MSFilter *f) {
bool_t success = FALSE;
JpegWriter *s=(JpegWriter*)f->data;
ms_filter_lock(f);
if (s->file != NULL && s->turboJpeg != NULL) {
int error;
MSPicture yuvbuf;
unsigned char *jpegBuffer = NULL;
unsigned long jpegSize = 0;
mblk_t *m=ms_queue_peek_last(f->inputs[0]);
if (ms_yuv_buf_init_from_mblk(&yuvbuf,m) != 0)
goto end;
error = tjCompressFromYUVPlanes(
s->turboJpeg,
(const unsigned char **)yuvbuf.planes,
yuvbuf.w,
yuvbuf.strides,
yuvbuf.h,
TJSAMP_420,
&jpegBuffer,
&jpegSize,
100,
TJFLAG_ACCURATEDCT
);
if (error != 0) {
ms_error("tjCompressFromYUVPlanes() failed: %s", tjGetErrorStr());
if (jpegBuffer != NULL) tjFree(jpegBuffer);
goto end;
}
if (fwrite(jpegBuffer, jpegSize, 1, s->file)>0) {
ms_message("Snapshot done with turbojpeg");
success = TRUE;
} else {
ms_error("Error writing snapshot.");
}
tjFree(jpegBuffer);
}
end:
cleanup(s, success);
ms_filter_unlock(f);
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",
.text = "Take a video snapshot as jpg file",
.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",
"Take a video snapshot as jpg file",
MS_FILTER_OTHER,
NULL,
1,
0,
jpg_init,
NULL,
jpg_process,
NULL,
jpg_uninit,
jpg_methods
};
#endif
MS_FILTER_DESC_EXPORT(ms_jpeg_writer_desc)
......@@ -23,6 +23,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
MS2_PUBLIC mblk_t *ms_load_jpeg_as_yuv(const char *path, MSVideoSize *reqsize);
MS2_PUBLIC mblk_t *ms_load_nowebcam(MSVideoSize *reqsize, int idx);
MS2_PUBLIC mblk_t *jpeg2yuv(uint8_t *jpgbuf, int bufsize, MSVideoSize *reqsize);
#endif
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