Guest User

Untitled

a guest
Aug 21st, 2019
155
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. //Copyright (c) 2019 Michael de Gans
  2. //
  3. //Permission is hereby granted, free of charge, to any person obtaining a copy
  4. // of this software and associated documentation files (the "Software"), to deal
  5. //in the Software without restriction, including without limitation the rights
  6. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. //copies of the Software, and to permit persons to whom the Software is
  8. //furnished to do so, subject to the following conditions:
  9. //
  10. //The above copyright notice and this permission notice shall be included in all
  11. // copies or substantial portions of the Software.
  12. //
  13. //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  19. //SOFTWARE.
  20.  
  21. #include "pipeline.h"
  22.  
  23. // these create the branches of the pipeline
  24. gboolean create_pipeline_begin(PipelineData* p_data);
  25. gboolean create_encoder_branch(PipelineData* p_data, const gchar* filename);
  26. gboolean create_nvinfer_branch(PipelineData* p_data);
  27.  
  28. // this links the entire pipeline together
  29. gboolean link_pipeline(PipelineData* p_data);
  30.  
  31. // main pipeline creation function
  32. gboolean create_pipeline_data(PipelineData* p_data, const gchar* filename) {
  33. // create the branches of the pipeline ...
  34. if (!create_pipeline_begin(p_data))
  35. return cleanup_pipeline_data(p_data);
  36. if (!create_encoder_branch(p_data, filename))
  37. return cleanup_pipeline_data(p_data);
  38. if (!create_nvinfer_branch(p_data))
  39. return cleanup_pipeline_data(p_data);
  40.  
  41. // ... and link them together
  42. if (!link_pipeline(p_data))
  43. return cleanup_pipeline_data(p_data);
  44.  
  45. // dump a pipeline graph to file
  46. GST_DEBUG_BIN_TO_DOT_FILE(GST_BIN(p_data->pipeline), GST_DEBUG_GRAPH_SHOW_ALL,
  47. "pipeline");
  48.  
  49. return TRUE;
  50. }
  51.  
  52. GstElement* create_and_add_element(GstPipeline* pipeline, const gchar* name) {
  53. // make an element
  54. GstElement* elem = gst_element_factory_make(name, name);
  55.  
  56. // verify if was created and fail if not
  57. if (!GST_IS_ELEMENT(elem)) {
  58. GST_ERROR(ERR_ELEM, name);
  59. return NULL;
  60. }
  61.  
  62. // add the element to the pipeline bin
  63. gst_bin_add(GST_BIN(pipeline), elem);
  64.  
  65. return elem;
  66. }
  67.  
  68. gboolean create_pipeline_begin(PipelineData* p_data) {
  69. // create a new Pipeline (Bin subclass) and check that it exists
  70. p_data->pipeline = GST_PIPELINE(gst_pipeline_new("pipeline"));
  71. if (!GST_IS_PIPELINE(p_data->pipeline)) {
  72. GST_ERROR(ERR_PIPELINE_CREATION);
  73. return FALSE;
  74. }
  75.  
  76. // a handy pointer to the bus to avoid having to call
  77. // gst_pipeline_get_bus repeatedly.
  78. // this must be unreferenced in the cleanup function.
  79. p_data->bus = gst_pipeline_get_bus(p_data->pipeline);
  80. if (!GST_IS_BUS(p_data->bus)) {
  81. GST_ERROR(ERR_BUS_GET);
  82. return FALSE;
  83. }
  84.  
  85. // create the camera, and add it to the Pipeline
  86. #ifdef IS_TEGRA // use the CSI camera, TODO: add usb camera support
  87. p_data->camera = create_and_add_element(p_data->pipeline, BC_CAMERA_CSI);
  88. if (!GST_IS_ELEMENT(p_data->camera)) {
  89. GST_ERROR(ERR_CAMERA_CREATION);
  90. return FALSE;
  91. }
  92. g_object_set(G_OBJECT(p_data->camera), "aeantibanding",
  93. 0, // disables flicker reduction
  94. "maxperf", TRUE, // enable argus maximum performance
  95. "ee-mode", 2, // edge enhancement off
  96. "tnr-mode", 2, // high quality temporal noise reduction
  97. NULL);
  98. #else
  99. // TODO(x86) make separate source and converter element
  100. GST_ERROR("X86 support unimplimentted");
  101. return FALSE;
  102. #endif
  103. // create a capsfilter element to tell the camera what we want sent downstream
  104. p_data->capsfilter =
  105. create_and_add_element(p_data->pipeline, BC_ELEM_CAPS_FILTER);
  106. if (p_data->capsfilter == NULL)
  107. return FALSE;
  108. g_object_set(G_OBJECT(p_data->capsfilter), "caps",
  109. gst_caps_from_string(BC_CAPS_STRING), NULL);
  110.  
  111. // create a tee (T) junction element to split the pipeline into two branches
  112. // (encoder branch and inference branch)
  113. p_data->tee = create_and_add_element(p_data->pipeline, BC_ELEM_TEE);
  114. if (p_data->tee == NULL)
  115. return FALSE;
  116.  
  117. return TRUE;
  118. }
  119.  
  120. gboolean create_encoder_branch(PipelineData* p_data, const gchar* filename) {
  121. // create the encoder queue to buffer data and run everything downstream
  122. // in it's own thread
  123. p_data->enc_queue = gst_element_factory_make(BC_ELEM_QUEUE, "enc_queue");
  124. if (!p_data->enc_queue) {
  125. GST_ERROR(ERR_ELEM, "(encoder) queue");
  126. return FALSE;
  127. }
  128. gst_bin_add(GST_BIN(p_data->pipeline), p_data->enc_queue);
  129.  
  130. // create and configure the h265 encoder
  131. p_data->encoder = create_and_add_element(p_data->pipeline, BC_ELEM_ENCODER);
  132. if (p_data->encoder == NULL)
  133. return FALSE;
  134. g_object_set(G_OBJECT(p_data->encoder), "bitrate", 4000000, NULL);
  135.  
  136. // create the parser
  137. p_data->parser = create_and_add_element(p_data->pipeline, BC_ELEM_PARSER);
  138. if (p_data->parser == NULL)
  139. return FALSE;
  140.  
  141. // create and configure the muxer
  142. p_data->muxer = create_and_add_element(p_data->pipeline, BC_ELEM_MUXER);
  143. if (p_data->muxer == NULL)
  144. return FALSE;
  145. g_object_set(G_OBJECT(p_data->muxer), "writing-app", "birbcam", NULL);
  146. // write index every minute so if something happens, the file will still be
  147. // seekable (probably, haven't tested this) TODO: test this
  148. g_object_set(G_OBJECT(p_data->muxer), "min-index-interval", (guint64)6e+10,
  149. NULL);
  150.  
  151. // filesink
  152. p_data->filesink = create_and_add_element(p_data->pipeline, BC_ELEM_FILESINK);
  153. if (p_data->filesink == NULL)
  154. return FALSE;
  155. g_object_set(G_OBJECT(p_data->filesink), "location", filename, NULL);
  156.  
  157. return TRUE;
  158. }
  159.  
  160. gboolean create_nvinfer_branch(PipelineData* p_data) {
  161. // create the inference queue to run everything downstream in it's own thread
  162. // and to buffer input
  163. p_data->infer_queue = gst_element_factory_make(BC_ELEM_QUEUE, "infer_queue");
  164. if (!p_data->infer_queue) {
  165. GST_ERROR("Could not create inference queue.");
  166. return FALSE;
  167. }
  168. gst_bin_add(GST_BIN(p_data->pipeline), p_data->infer_queue);
  169.  
  170. // create nvstreammux element to add the metadata
  171. p_data->streammux =
  172. create_and_add_element(p_data->pipeline, BC_ELEM_STREAM_MUX);
  173. if (p_data->streammux == NULL)
  174. return FALSE;
  175. g_object_set(G_OBJECT(p_data->streammux), "batch-size", 1, "width", 384,
  176. "height", 216, NULL);
  177.  
  178. // create primary inference element (no secondary as of yet, maybe use the
  179. // Coral, but will need to write a plugin for that since Google's is written
  180. // in python, no really)
  181. p_data->infer = create_and_add_element(p_data->pipeline, BC_ELEM_INFERENCE);
  182. if (p_data->infer == NULL)
  183. return FALSE;
  184. g_object_set(G_OBJECT(p_data->infer), "config-file-path", "../birbcam.cfg",
  185. NULL);
  186.  
  187. // create a fakesink, onto which a probe will be attached to call on_batch
  188. // for each batch of frames to parse the metadata
  189. p_data->fakesink = create_and_add_element(p_data->pipeline, BC_ELEM_FAKESINK);
  190. if (p_data->fakesink == NULL) {
  191. return FALSE;
  192. }
  193. return TRUE;
  194. }
  195.  
  196. gboolean link_pipeline(PipelineData* p_data) {
  197. #ifdef IS_TEGRA
  198. // link pipeline beginning
  199. if (!gst_element_link_many(p_data->camera, p_data->capsfilter, p_data->tee,
  200. NULL)) {
  201. // "Could not link pipeline %s."
  202. GST_ERROR(ERR_LINK, "beginning");
  203. return FALSE;
  204. }
  205. #else // X86
  206. // link: camera, converter, capsfilter, tee
  207. #endif
  208. // link and connect encoder branch
  209. if (!gst_element_link_many(p_data->enc_queue, p_data->encoder, p_data->parser,
  210. p_data->muxer, p_data->filesink, NULL)) {
  211. GST_ERROR(ERR_LINK, "encoder branch");
  212. return FALSE;
  213. }
  214.  
  215. // // link and connect inference branch
  216. if (!gst_element_link_pads(p_data->infer_queue, "src", p_data->streammux,
  217. "sink_0")) {
  218. GST_ERROR(ERR_LINK, "inference queue and stream muxer");
  219. return FALSE;
  220. }
  221. if (!gst_element_link_many(p_data->streammux, p_data->infer, p_data->fakesink,
  222. NULL)) {
  223. GST_ERROR(ERR_LINK, "inference branch");
  224. return FALSE;
  225. }
  226.  
  227. // link the branches to the tee
  228. if (!gst_element_link(p_data->tee, p_data->enc_queue)) {
  229. GST_ERROR(ERR_LINK, "tee and encoder queue");
  230. }
  231. if (!gst_element_link(p_data->tee, p_data->infer_queue)) {
  232. GST_ERROR(ERR_LINK, "tee and inference queue");
  233. }
  234.  
  235.  
  236. return TRUE;
  237. }
  238.  
  239. gboolean shutdown_pipeline(PipelineData* p_data) {
  240. // set the pipeline to the playing state
  241. gst_element_set_state(GST_ELEMENT(p_data->pipeline), GST_STATE_NULL);
  242. }
  243.  
  244. gboolean cleanup_pipeline_data(PipelineData* p_data) {
  245. // unreference the bus because gst_pipeline_get_bus requires it
  246. if (p_data->bus) {
  247. gst_object_unref(p_data->bus);
  248. }
  249. shutdown_pipeline(p_data);
  250. // unreference the pipeline (and all elements added to it implicitly)
  251. if (p_data->pipeline)
  252. gst_object_unref(p_data->pipeline);
  253. return FALSE;
  254. }
RAW Paste Data

Adblocker detected! Please consider disabling it...

We've detected AdBlock Plus or some other adblocking software preventing Pastebin.com from fully loading.

We don't have any obnoxious sound, or popup ads, we actively block these annoying types of ads!

Please add Pastebin.com to your ad blocker whitelist or disable your adblocking software.

×