Author: carlsonlee (carlsonlee.freec@hotmail.com), part of freecamera, freecamera source code exists: http://gitorious.org/freecamera
# Include <glib. h>
# Include <string. h>
# Include <stdio. h>
# Include <unistd. h>
# Include <stdlib. h>
# Include <pthread. h>
# Include <GST/GST. h>
# Include <GST/APP/stststappsink. h>
# Include <GST/APP/stststappsrc. h>
# Include <GST/APP/gstappbuffer. h>
# Include "cam_midware.h"
# Include "cam_global.h"
# Include "cam_display.h"
# Include "cam_files.h"
# Include "color_space.h"
# Include "review_data.h"
# Include "cam_ui.h"
# Include "cam_utils.h"
# Include "cam_err.h"
# Define skip_frames 10
Static struct tag_cam_mw_data
{
Gint camera_status;
Gmainloop * video_cap_loop;
Char * filename;
Gint skip_frames;
Gmutex * mutex;
} Cam_video_data;
Static gboolean video_bus_call (gstbus * bus,
Stststmessage * MSG,
Gpointer data)
{
Gmainloop * loop = (gmainloop *) data;
Bus = bus;
Switch (maid (MSG ))
{
Case ststst_message_eos:
G_main_loop_quit (loop );
Break;
Case ststst_message_error:
{
Gchar * debug;
Gerror * error;
Ststst_message_parse_error (MSG, & error, & Debug );
G_print ("error ** ##: % s, % s \ n", error-> message, debug );
G_free (Debug );
G_error_free (error );
G_main_loop_quit (loop );
}
Break;
Default:
Break;
}
Return true;
}
Static gboolean link_video_cap_src (ststelement * SRC, ststelement * sink)
{
Gboolean link_ OK = false;
Gstcaps * caps;
Guint width = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. width;
Guint Height = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. height;
Caps = maid ("Video/X-raw-YUV ",
"Width", g_type_int, width,
"Height", g_type_int, height, null );
Link_ OK = maid (SRC, sink, caps );
Ststst_caps_unref (CAPS );
Return link_ OK;
}
Static gboolean link_video_cap_pp (ststelement * SRC, ststelement * sink)
{
Gboolean link_ OK = false;
Gstcaps * caps;
Guint width = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. width;
Guint Height = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. height;
Caps = maid ("Video/X-raw-YUV ",
"Format", maid, maid ('I, '4', '2', '0 '),
"Width", g_type_int, width,
"Height", g_type_int, height, null );
Link_ OK = maid (SRC, sink, caps );
Ststst_caps_unref (CAPS );
Return link_ OK;
}
Static gboolean link_video_cap_enc (ststelement * SRC, ststelement * sink)
{
Gboolean link_ OK = false;
Gstcaps * caps;
Guint width = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. width;
Guint Height = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. height;
Caps = maid ("Video/X-raw-YUV ",
"Format", maid, maid ('I, '4', '2', '0 '),
"Framerate", maid, 30, 1,
"Width", g_type_int, width,
"Height", g_type_int, height, null );
Link_ OK = maid (SRC, sink, caps );
Ststst_caps_unref (CAPS );
Return link_ OK;
}
Gint gettickcount ()
{
Struct timeval TV;
Gettimeofday (& TV, null );
Return (TV. TV _sec * 1000 + TV. TV _usec/1000 );
}
Static Gint frames = 0;
Static long last_time = 0;
Static void raw_captured (void * data, guint size, guint64 timestamp)
{
Guint width = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. width;
Guint Height = cam_global_data.cam_res.video_res [cam_global_data.cam_res.video_res_cur]. height;
If (cam_global_data.photo_timestamp)
Camui_mask_timestamp (data, width, height );
If (cam_video_data.skip_frames -- <= 0)
{
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;
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 );
}
Camrev_append (review_data, cam_video_data.filename );
}
Frames ++;
If (frames % 30 = 0)
{
G_print ("FPS: % LD \ n", 30000/(gettickcount ()-last_time ));
Last_time = gettickcount ();
Frames = 0;
}
Camdisp_show (data,
Width * height * 3/2,
Width,
Height );
Cam_global_data.video_rec_time = timestamp/1000000000;
}
Void * video_cap_thread (void * PARAM)
{
Const char * cam_dev_file = cam_global_data.cam_dev_list-> cam_device [cam_global_data.cam_dev_list-> current_device]. device;
Ststbus * video_cap_bus = NULL;
Ststelement * video_cap_pipeline = NULL;
Ststelement * video_cap_bin = NULL;
Ststelement * video_cap_src = NULL;
Ststelement * video_cap_pp = NULL;
Ststelement * video_cap_trans = NULL;
Ststelement * video_cap_enc = NULL;
Ststelement * video_cap_mux = NULL;
Ststelement * video_cap_sink = NULL;
Ststelement * audio_cap_src = NULL;
Ststamp element * audio_cap_enc = NULL;
Maid * srcpad = NULL;
Gstpad * sinkpad = NULL;
Maid;
Gboolean ret = false;
Cam_global_data.is_capturing = true;
Cam_video_data.skip_frames = skip_frames;
Cammw_stop_preview ();
Camrev_init (cam_global_data.preview_data_width, cam_global_data.preview_data_height );
Cam_video_data.video_cap_loop = g_main_loop_new (null, false );
Video_cap_pipeline = maid ("video_cap ");
If (! Video_cap_pipeline)
{
G_print ("% s, % d \ n", _ FUNCTION __, _ line __);
Goto exit;
}
Video_cap_bus = maid (maid ));
Ststst_bus_add_watch (video_cap_bus, video_bus_call, cam_video_data.video_cap_loop );
Stst_object_unref (video_cap_bus );
Video_cap_bin = maid ("video_cap_bin ");
Video_cap_src = maid ("v4l2src", "video_cap_src ");
Video_cap_pp = maid ("ffmpegcolorspace", "video_pp ");
Video_cap_trans = maid ("camgrub", "video_enc_trans ");
Video_cap_enc = maid ("theoraenc", "video_enc ");
Video_cap_mux = maid ("oggmux", "video_mux ");
Video_cap_sink = maid ("filesink", "video_writer ");
Audio_cap_src = maid ("pulsesrc", "audio_cap_src ");
Audio_cap_enc = maid ("vorbisenc", "audio_cap_enc ");
If (! Video_cap_bin |
! Video_cap_src |
! Video_cap_pp |
! Video_cap_trans |
! Video_cap_enc |
! Video_cap_mux |
! Video_cap_sink |
! Audio_cap_src |
! Audio_cap_enc
)
{
G_printerr ("one element in capture bin cocould not be created. exiting. \ n ");
Goto exit;
}
G_object_set (g_object (video_cap_src), "device", cam_dev_file, null );
G_object_set (g_object (video_cap_trans), "captured", (guint) raw_captured, null );
Cam_video_data.filename = g_strdup (camfiles_get_video_full_name ());
G_object_set (g_object (video_cap_sink), "location", cam_video_data.filename, null );
Ststst_bin_add_many (stst_bin (video_cap_bin ),
Video_cap_src,
Video_cap_pp,
Video_cap_trans,
Video_cap_enc,
Video_cap_mux,
Video_cap_sink,
Audio_cap_src,
Audio_cap_enc,
Null );
Ststst_bin_add (ststst_bin (video_cap_pipeline), video_cap_bin );
If (! Link_video_cap_src (video_cap_src, video_cap_pp ))
{
G_print ("link camera SRC element failed \ n ");
Goto exit;
}
If (! Link_video_cap_pp (video_cap_pp, video_cap_trans ))
{
G_print ("link camera pp element failed \ n ");
Goto exit;
}
If (! Link_video_cap_enc (video_cap_trans, video_cap_enc ))
{
G_print ("link camera video ENC elements failed \ n ");
Goto exit;
}
/* If (! Ststst_element_link_many (video_cap_pp, video_cap_enc, null ))
{
G_print ("link camera audio ENC elements failed \ n ");
Goto exit;
}*/
If (! Ststst_element_link_many (audio_cap_src, audio_cap_enc, null ))
{
G_print ("link camera audio ENC elements failed \ n ");
Goto exit;
}
Sinkpad = maid (video_cap_mux, "sink_0 ");
Srcpad = maid (video_cap_enc, "src ");
Lres = maid (srcpad, sinkpad );
If (lres! = Maid)
{
G_print ("link camera video MUX elements failed \ n ");
Goto exit;
}
// Maid (video_cap_mux, sinkpad );
Stst_object_unref (srcpad );
Sinkpad = maid (video_cap_mux, "sink_1 ");
Srcpad = maid (audio_cap_enc, "src ");
Lres = maid (srcpad, sinkpad );
Stst_object_unref (srcpad );
If (lres! = Maid)
{
G_print ("link camera audio MUX elements failed \ n ");
Goto exit;
}
If (! Ststst_element_link_ux (video_cap_mux, video_cap_sink, null ))
{
G_print ("link camera video filesink elements failed \ n ");
Goto exit;
}
Ststst_element_set_state (video_cap_pipeline, stst_state_playing );
Cam_video_data.camera_status = cam_status_running;
G_mutex_unlock (cam_video_data.mutex );
Camutils_play_record_sound ();
G_main_loop_run (cam_video_data.video_cap_loop );
Ststst_element_set_state (video_cap_pipeline, stst_state_null );
Camutils_play_record_sound ();
Ret = true;
Exit:
If (video_cap_pipeline)
Ststst_object_unref (stst_object (video_cap_pipeline ));
If (cam_video_data.video_cap_loop)
G_main_loop_unref (cam_video_data.video_cap_loop );
If (cam_video_data.filename)
G_free (cam_video_data.filename );
Cam_video_data.camera_status = cam_status_stopped;
If (! RET)
{
Camui_show_error_message (cerr_failed_record_video );
Cam_global_data.is_capturing = false;
G_mutex_unlock (cam_video_data.mutex );
}
Return NULL;
}
Gboolean cammw_start_record_video ()
{
Pthread_t thread_id;
Pthread_attr_t ATTR;
If (cam_video_data.camera_status = cam_status_running)
Return false;
Memset (& cam_video_data, 0, sizeof (cam_video_data ));
Cam_video_data.mutex = g_mutex_new ();
G_mutex_lock (cam_video_data.mutex );
Pthread_attr_init (& ATTR );
Pthread_create (& thread_id, null, video_cap_thread, null );
While (! G_mutex_trylock (cam_video_data.mutex ))
{
Usleep (100000 );
}
G_mutex_unlock (cam_video_data.mutex );
If (cam_video_data.camera_status = cam_status_stopped)
{
G_mutex_free (cam_video_data.mutex );
If (cam_video_data.video_cap_loop)
G_main_loop_unref (cam_video_data.video_cap_loop );
Memset (& cam_video_data, 0, sizeof (cam_video_data ));
Return false;
}
Return true;
}
Gboolean cammw_stop_record_video ()
{
If (cam_video_data.camera_status! = Cam_status_running)
Return true;
G_mutex_free (cam_video_data.mutex );
G_main_loop_quit (cam_video_data.video_cap_loop );
Memset (& cam_video_data, 0, sizeof (cam_video_data ));
Cam_global_data.is_capturing = false;
Return true;
}