#include <gstappsink.hpp>
#include <gst.hpp>
#include <glib.h>
#include <glib-object.h>
#include <iostream>
#define FILENAME "sampleCar.pcap"

int main()
{
    gst_init(NULL, NULL);
    // Construct the URI of the file to be read
    // g_filename_to_uri() adds the "file://" prefix and escapes the special characters in the filename    
    const gchar *fullURI = g_filename_to_uri( FILENAME, NULL, NULL ); 
    if (fullURI == NULL)
        std::cout<<FILENAME<<"\nURI is null"<<std::flush;
    
    // Run the following at least 3 times
    for (int i = 0; i<3; i++) 
    {
    // Create the playbin element
    GstElement* playbin = gst_element_factory_make("playbin", "tmwplaybin");
    if( playbin != NULL ){
        std::cout<< "\nPlaybin initializated successfully"<<"\n"<<std::flush;}    
        else{
            std::cout<< "\nPlaybin initialization failed"<<"\n"<<std::flush;
            return 0;
        }
        

    // Create the appsink element
    GstElement* _appsink = gst_element_factory_make("appsink", "tmwvideoappsink");
    if( _appsink == NULL ){
        std::cout<<"\nCould not create appsink";}
    
    // Specify the appsink caps to return 24-bit RGB data
    // The appsink will take ownership of the caps and so there is no need to clean it here.
    GstCaps* caps = gst_caps_from_string("video/x-raw, format = {RGB}");
    
    gst_app_sink_set_caps( GST_APP_SINK(_appsink), caps );
    GST_INFO("RGB caps set on the Appsink");
    
    // Specify the maximum number of buffers that the appsink can queue when the 
    // pipeline is running
    gst_app_sink_set_max_buffers(GST_APP_SINK(_appsink), 1);

    // Specify that the appsink should not drop any samples when more buffers are received
    // than it can queue
    gst_app_sink_set_drop(GST_APP_SINK(_appsink), false);

    std::cout<<"\nAppsink has been created"<<"\n"<<std::flush;

    // Set the URI property of the playbin
    g_object_set( playbin, "uri", fullURI, NULL );

    // Set the video-sink property of playbin to be the appsink
    // Note: As the newly created appsink is now a property of playbin, 
    // its lifetime is managed by playbin
    g_object_set( G_OBJECT(playbin), "video-sink", _appsink, NULL );

    // Suppress the audio, text and sub-pic outputs of playbin
    // Note: As the newly created appsink is now a property of playbin, 
    // its lifetime is managed by playbin
    GstElement* fakesinkAudio = gst_element_factory_make("fakesink", "tmwfakeaudiosink");
    g_object_set( G_OBJECT(playbin), "audio-sink", fakesinkAudio, NULL );

    // Note: As the newly created appsink is now a property of playbin, 
    // its lifetime is managed by playbin
    GstElement* fakesinkText = gst_element_factory_make("fakesink", "tmwfaketextsink");
    g_object_set( G_OBJECT(playbin), "text-sink", fakesinkText, NULL );

    // Disable clocking for the pipeline to run as fast as possible
    gst_pipeline_use_clock( GST_PIPELINE(playbin), NULL );

    GST_INFO("playbin initialization has been completed");

    // Set the pipeline state to PAUSED to prepare the elements for streaming
    // This will ensure that all caps are negotiated.
    GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
    ret = gst_element_set_state(playbin, GST_STATE_PAUSED);
    if( ret == GST_STATE_CHANGE_FAILURE )
    {
        std::cout<<"\nState change to PAUSE failed";
        return 0;
    }

    // Verify that the state change to the desired state has completed successfully
    ret = gst_element_get_state(playbin, NULL, NULL, GST_SECOND * 5);
    if( (ret == GST_STATE_CHANGE_FAILURE) || (ret == GST_STATE_CHANGE_NO_PREROLL) )
    {
       std::cout<<"\nState change to PAUSE failed";
       return 0;
    }   
        
    std::cout<<"\nplaybin successfully changed to PAUSED"<<"\n"<<std::flush;  
    
    // Set the pipeline state to PLAYING 
    ret = GST_STATE_CHANGE_SUCCESS;
    ret = gst_element_set_state(playbin, GST_STATE_PLAYING);
    if( ret == GST_STATE_CHANGE_FAILURE )
    {
        std::cout<<"\nState change to PLAYING failed";
        return 0;
    }

    // Verify that the state change to the desired state has completed successfully
    ret = gst_element_get_state(playbin, NULL, NULL, GST_SECOND * 5);
    if( (ret == GST_STATE_CHANGE_FAILURE) || (ret == GST_STATE_CHANGE_NO_PREROLL) )
    {
       std::cout<<"\nState change to PLAYING failed";
       return 0;
    }   
        
    std::cout<<"\nplaybin successfully changed to PLAYING"<<"\n"<<std::flush; 
    
    // Set the pipeline state to NULL 
    ret = GST_STATE_CHANGE_SUCCESS;
    ret = gst_element_set_state(playbin, GST_STATE_NULL);
    if( ret == GST_STATE_CHANGE_FAILURE )
    {
       std::cout<<"\nState change to NULL failed";
       return 0;
    }

    // Verify that the state change to the desired state has completed successfully
    ret = gst_element_get_state(playbin, NULL, NULL, GST_SECOND * 5);
    if( (ret == GST_STATE_CHANGE_FAILURE) || (ret == GST_STATE_CHANGE_NO_PREROLL) )
    {
       std::cout<<"\nState change to NULL failed";
       return 0;
    }   
        
    std::cout<<"\nplaybin successfully changed to NULL"<<"\n"<<std::flush;    
    
    gst_object_unref(playbin); 
    }
    return 0;
    }
