linux下webcam进行拍照, gstreamer架构

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;
}

(carlsonlee_freec)

你可能感兴趣的:(linux,linux,linux,gstreamer)