author: CarlsonLee([email protected]), 本代码是freecamera的一部分,freecamera源代码存在:http://gitorious.org/freecamera
#include <glib.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <gst/gst.h>
#include <gst/app/gstappsink.h>
#include <gst/app/gstappsrc.h>
#include <gst/app/gstappbuffer.h>
#include "cam_midware.h"
#include "cam_global.h"
#include "cam_display.h"
#include "cam_files.h"
#include "review_data.h"
#include "color_space.h"
#include "cam_ui.h"
#include "cam_utils.h"
#include "cam_err.h"
static struct tag_CAM_MW_DATA
{
gint camera_status;
gint need_capture_frame;
GMainLoop* cam_photo_cap_loop;
gchar* last_capture_filename;
}cam_photo_data;
static gboolean photo_bus_call (GstBus *bus,
GstMessage *msg,
gpointer data)
{
GMainLoop *loop = (GMainLoop *) data;
bus = bus;
switch (GST_MESSAGE_TYPE (msg))
{
case GST_MESSAGE_EOS:
g_main_loop_quit (loop);
break;
case GST_MESSAGE_ERROR:
{
gchar *debug;
GError *error;
gst_message_parse_error (msg, &error, &debug);
g_free (debug);
g_print ("Error**##: %s\n", error->message);
g_error_free (error);
g_main_loop_quit (loop);
}
break;
default:
break;
}
return TRUE;
}
static gboolean link_photo_cap_src(GstElement *src, GstElement *sink)
{
gboolean link_ok = FALSE;
GstCaps *caps;
guint width = cam_global_data.cam_res.photo_res[cam_global_data.cam_res.photo_res_cur].width;
guint height = cam_global_data.cam_res.photo_res[cam_global_data.cam_res.photo_res_cur].height;
caps = gst_caps_new_simple ("video/x-raw-yuv",
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height, NULL);
link_ok = gst_element_link_filtered (src, sink, caps);
gst_caps_unref (caps);
return link_ok;
}
static gboolean link_photo_cap_pp(GstElement *src, GstElement *sink)
{
gboolean link_ok = FALSE;
GstCaps *caps;
guint width = cam_global_data.cam_res.photo_res[cam_global_data.cam_res.photo_res_cur].width;
guint height = cam_global_data.cam_res.photo_res[cam_global_data.cam_res.photo_res_cur].height;
caps = gst_caps_new_simple ("video/x-raw-yuv",
"format", GST_TYPE_FOURCC, UI_COLOR_FORMAT,
"width", G_TYPE_INT, width,
"height", G_TYPE_INT, height, NULL);
link_ok = gst_element_link_filtered (src, sink, caps);
gst_caps_unref (caps);
return link_ok;
}
static void on_new_photo_buffer(GstElement * elt, void* param)
{
GstBuffer *buffer;
if(cam_photo_data.last_capture_filename==NULL)
return;
if(cam_photo_data.need_capture_frame<=0)
goto exit;
FILE *fp = fopen(cam_photo_data.last_capture_filename, "wb");
if(fp == NULL)
goto exit;
buffer = gst_app_sink_pull_buffer (GST_APP_SINK (elt));
fwrite(GST_BUFFER_DATA(buffer), 1, GST_BUFFER_SIZE(buffer), fp);
fclose(fp);
gst_buffer_unref (buffer);
g_print("save one photo : %s\n", cam_photo_data.last_capture_filename);
if((--cam_photo_data.need_capture_frame)<=0)
g_main_loop_quit(cam_photo_data.cam_photo_cap_loop);
exit:
if(cam_photo_data.last_capture_filename)
g_free(cam_photo_data.last_capture_filename);
cam_photo_data.last_capture_filename = NULL;
}
static void raw_captured(void* data, guint size, guint64 timestamp)
{
guint width = cam_global_data.cam_res.photo_res[cam_global_data.cam_res.photo_res_cur].width;
guint height = cam_global_data.cam_res.photo_res[cam_global_data.cam_res.photo_res_cur].height;
void* review_data = malloc(cam_global_data.preview_data_width*cam_global_data.preview_data_height*3/2);
timestamp = timestamp;
if(review_data == NULL)
return;
camutils_play_shutter_sound();
if(cam_global_data.photo_timestamp)
{
g_print("photo_timestamp\n");
camui_mask_timestamp(data, width, height);
}
if(width != cam_global_data.preview_data_width || height != cam_global_data.preview_data_height)
{
resample_yv12(review_data,
cam_global_data.preview_data_width,
cam_global_data.preview_data_height,
data, width, height, SCALE_TYPE_BILINEAR);
}
else
{
memcpy(review_data, data, cam_global_data.preview_data_width*cam_global_data.preview_data_height*3/2);
}
camdisp_show(review_data,
cam_global_data.preview_data_width*cam_global_data.preview_data_height*3/2,
cam_global_data.preview_data_width,
cam_global_data.preview_data_height);
cam_photo_data.last_capture_filename = g_strdup(camfiles_get_photo_full_name());
camrev_append(review_data, cam_photo_data.last_capture_filename);
usleep(200000);
g_print("grab one raw frame\n");
}
static gint get_photo_quality()
{
gint quality = 85;
switch(cam_global_data.photo_quality)
{
default:
case PHOTO_QUALITY_BASIC:
quality = 80;
break;
case PHOTO_QUALITY_NORMAL:
quality = 90;
break;
case PHOTO_QUALITY_FINE:
quality = 95;
break;
}
return quality;
}
gboolean cammw_capture_photo()
{
const char* cam_dev_file = cam_global_data.cam_dev_list->cam_device[cam_global_data.cam_dev_list->current_device].device;
GstBus *cam_photo_cap_bus = NULL;
GstElement *cam_photo_cap_pipeline = NULL;
GstElement *cam_photo_cap_bin = NULL;
GstElement *cam_photo_cap_src = NULL;
GstElement *cam_photo_cap_pp = NULL;
GstElement *cam_photo_cap_trans = NULL;
GstElement *cam_photo_cap_enc = NULL;
GstElement *cam_photo_cap_sink = NULL;
gboolean ret = FALSE;
cam_global_data.is_capturing = TRUE;
memset(&cam_photo_data, 0, sizeof(cam_photo_data));
cammw_stop_preview();
camrev_init(cam_global_data.preview_data_width, cam_global_data.preview_data_height);
switch(cam_global_data.photo_burst)
{
default:
case PHOTO_BURST_0:
cam_photo_data.need_capture_frame = 1;
break;
case PHOTO_BURST_3:
cam_photo_data.need_capture_frame = 3;
break;
case PHOTO_BURST_5:
cam_photo_data.need_capture_frame = 5;
break;
case PHOTO_BURST_10:
cam_photo_data.need_capture_frame = 10;
break;
}
cam_photo_data.cam_photo_cap_loop = g_main_loop_new(NULL, FALSE);
if(cam_photo_data.cam_photo_cap_loop == NULL)
{
g_print("%s, %d\n", __FUNCTION__, __LINE__);
goto exit;
}
//photo capture
cam_photo_cap_pipeline = gst_pipeline_new ("cam_photo_cap");
if(!cam_photo_cap_pipeline)
{
g_print("%s, %d\n", __FUNCTION__, __LINE__);
goto exit;
}
cam_photo_cap_bus = gst_pipeline_get_bus (GST_PIPELINE (cam_photo_cap_pipeline));
gst_bus_add_watch (cam_photo_cap_bus, photo_bus_call, cam_photo_data.cam_photo_cap_loop);
gst_object_unref (cam_photo_cap_bus);
cam_photo_cap_bin = gst_bin_new("photo_cap_bin");
cam_photo_cap_src = gst_element_factory_make ("v4l2src", "photo_cap_src");
cam_photo_cap_pp = gst_element_factory_make ("ffmpegcolorspace", "cam_photo_pp");
cam_photo_cap_trans = gst_element_factory_make ("camgrub","photo_enc_trans");
cam_photo_cap_enc = gst_element_factory_make ("jpegenc","photo_enc_sink");
cam_photo_cap_sink = gst_element_factory_make ("appsink","photo_cap_sink");
if ( !cam_photo_cap_bin ||
!cam_photo_cap_src ||
!cam_photo_cap_pp ||
!cam_photo_cap_trans||
!cam_photo_cap_enc ||
!cam_photo_cap_sink )
{
g_printerr ("One element in capture bin could not be created. Exiting.\n");
goto exit ;
}
g_object_set (G_OBJECT (cam_photo_cap_src), "device", cam_dev_file, NULL);
gst_app_sink_set_emit_signals((GstAppSink *)cam_photo_cap_sink, TRUE);
g_signal_connect (cam_photo_cap_sink, "new-buffer", G_CALLBACK (on_new_photo_buffer), NULL);
g_object_set (G_OBJECT (cam_photo_cap_trans), "skip-frames", 10, NULL);
g_object_set (G_OBJECT (cam_photo_cap_trans), "captured", (guint)raw_captured, NULL);
g_object_set (G_OBJECT (cam_photo_cap_enc), "quality", (guint)get_photo_quality(), NULL);
gst_bin_add_many (GST_BIN (cam_photo_cap_bin),
cam_photo_cap_src,
cam_photo_cap_pp,
cam_photo_cap_trans,
cam_photo_cap_enc,
cam_photo_cap_sink,
NULL);
gst_bin_add (GST_BIN (cam_photo_cap_pipeline), cam_photo_cap_bin);
if(!link_photo_cap_src (cam_photo_cap_src, cam_photo_cap_pp))
{
g_print("link camera src element failed\n");
goto exit;
}
if(!link_photo_cap_pp (cam_photo_cap_pp, cam_photo_cap_trans))
{
g_print("link camera pp element failed\n");
goto exit;
}
if(!gst_element_link_many (cam_photo_cap_trans,cam_photo_cap_enc,cam_photo_cap_sink, NULL))
{
g_print("link camera other elements failed\n");
goto exit;
}
gst_element_set_state (cam_photo_cap_pipeline, GST_STATE_PLAYING);
cam_photo_data.camera_status = CAM_STATUS_RUNNING;
g_main_loop_run(cam_photo_data.cam_photo_cap_loop);
gst_element_set_state (cam_photo_cap_pipeline, GST_STATE_NULL);
ret = TRUE;
exit:
if(!ret)
{
camui_show_error_message(CERR_FAILED_CAPTURE_PHOTO);
}
if(cam_photo_cap_pipeline)
gst_object_unref (GST_OBJECT (cam_photo_cap_pipeline));
if(cam_photo_data.cam_photo_cap_loop)
g_main_loop_unref(cam_photo_data.cam_photo_cap_loop);
cam_photo_data.camera_status = CAM_STATUS_STOPPED;
cam_global_data.is_capturing = FALSE;
return ret;
}