LCOV - code coverage report
Current view: top level - filters - out_pipe.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 94 150 62.7 %
Date: 2021-04-29 23:48:07 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  *                      GPAC - Multimedia Framework C SDK
       3             :  *
       4             :  *                      Authors: Jean Le Feuvre
       5             :  *                      Copyright (c) Telecom ParisTech 2018
       6             :  *                                      All rights reserved
       7             :  *
       8             :  *  This file is part of GPAC / generic pipe output filter
       9             :  *
      10             :  *  GPAC is free software; you can redistribute it and/or modify
      11             :  *  it under the terms of the GNU Lesser General Public License as published by
      12             :  *  the Free Software Foundation; either version 2, or (at your option)
      13             :  *  any later version.
      14             :  *
      15             :  *  GPAC is distributed in the hope that it will be useful,
      16             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      17             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      18             :  *  GNU Lesser General Public License for more details.
      19             :  *
      20             :  *  You should have received a copy of the GNU Lesser General Public
      21             :  *  License along with this library; see the file COPYING.  If not, write to
      22             :  *  the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
      23             :  *
      24             :  */
      25             : 
      26             : 
      27             : #include <gpac/filters.h>
      28             : #include <gpac/constants.h>
      29             : 
      30             : #ifdef WIN32
      31             : 
      32             : #include <windows.h>
      33             : 
      34             : #else
      35             : 
      36             : #include <fcntl.h>
      37             : #include <unistd.h>
      38             : 
      39             : #ifdef GPAC_CONFIG_LINUX
      40             : #include <sys/types.h>
      41             : #include <sys/stat.h>
      42             : #endif
      43             : 
      44             : #ifndef __BEOS__
      45             : #include <errno.h>
      46             : #endif
      47             : 
      48             : #endif
      49             : 
      50             : 
      51             : 
      52             : typedef struct
      53             : {
      54             :         //options
      55             :         Double start, speed;
      56             :         char *dst, *mime, *ext;
      57             :         Bool dynext, mkp;
      58             :         u32 block_size;
      59             : 
      60             : 
      61             :         //only one input pid
      62             :         GF_FilterPid *pid;
      63             : 
      64             : #ifdef WIN32
      65             :         HANDLE pipe;
      66             : #else
      67             :         int fd;
      68             : #endif
      69             : 
      70             :         GF_FilterCapability in_caps[2];
      71             :         char szExt[10];
      72             :         char szFileName[GF_MAX_PATH];
      73             :         Bool owns_pipe;
      74             : 
      75             : } GF_PipeOutCtx;
      76             : 
      77             : const char *gf_errno_str(int errnoval);
      78             : 
      79             : 
      80          28 : static GF_Err pipeout_open_close(GF_PipeOutCtx *ctx, const char *filename, const char *ext, u32 file_idx, Bool explicit_overwrite)
      81             : {
      82             :         GF_Err e = GF_OK;
      83             :         char szName[GF_MAX_PATH], szFinalName[GF_MAX_PATH];
      84             : 
      85          28 :         if (!filename) {
      86             : #ifdef WIN32
      87             :                 if (ctx->pipe != INVALID_HANDLE_VALUE) CloseHandle(ctx->pipe);
      88             :                 ctx->pipe = INVALID_HANDLE_VALUE;
      89             : #else
      90          20 :                 if (ctx->fd>=0) close(ctx->fd);
      91          20 :                 ctx->fd = -1;
      92             : #endif
      93             :                 return GF_OK;
      94             :         }
      95             : 
      96           8 :         if (!strncmp(filename, "pipe://", 7)) filename+=7;
      97             : 
      98           8 :         if (ctx->dynext) {
      99           0 :                 Bool has_ext = (strchr(filename, '.')==NULL) ? GF_FALSE : GF_TRUE;
     100             : 
     101             :                 strcpy(szName, filename);
     102           0 :                 if (!has_ext && ext) {
     103             :                         strcat(szName, ".");
     104             :                         strcat(szName, ext);
     105             :                 }
     106             :         } else {
     107             :                 strcpy(szName, filename);
     108             :         }
     109           8 :         gf_filter_pid_resolve_file_template(ctx->pid, szName, szFinalName, file_idx, NULL);
     110             : 
     111           8 :         if (!strcmp(szFinalName, ctx->szFileName) 
     112             : #ifdef WIN32
     113             :                 && (ctx->pipe != INVALID_HANDLE_VALUE)
     114             : #else
     115           0 :                 && ctx->fd>=0
     116             : #endif
     117             :                 ) return GF_OK;
     118             : 
     119             : #ifdef WIN32
     120             :         if (ctx->pipe != INVALID_HANDLE_VALUE) CloseHandle(ctx->pipe);
     121             :         ctx->pipe = INVALID_HANDLE_VALUE;
     122             :         char szNamedPipe[GF_MAX_PATH];
     123             :         if (!strncmp(szFinalName, "\\\\", 2)) {
     124             :                 strcpy(szNamedPipe, szFinalName);
     125             :         }
     126             :         else {
     127             :                 strcpy(szNamedPipe, "\\\\.\\pipe\\gpac\\");
     128             :                 strcat(szNamedPipe, szFinalName);
     129             :         }
     130             :         if (strchr(szFinalName, '/')) {
     131             :                 u32 i, len = (u32)strlen(szNamedPipe);
     132             :                 for (i = 0; i < len; i++) {
     133             :                         if (szNamedPipe[i] == '/')
     134             :                                 szNamedPipe[i] = '\\';
     135             :                 }
     136             :         }
     137             : 
     138             :         if (WaitNamedPipeA(szNamedPipe, 1) == FALSE) {
     139             :                 if (!ctx->mkp) {
     140             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Failed to open %s: %d\n", szNamedPipe, GetLastError()));
     141             :                         e = GF_URL_ERROR;
     142             :                 }
     143             :                 else {
     144             :                         ctx->pipe = CreateNamedPipe(szNamedPipe, PIPE_ACCESS_OUTBOUND | FILE_FLAG_FIRST_PIPE_INSTANCE,
     145             :                                 PIPE_TYPE_BYTE | PIPE_WAIT,
     146             :                                 10,
     147             :                                 ctx->block_size,
     148             :                                 ctx->block_size,
     149             :                                 0,
     150             :                                 NULL);
     151             : 
     152             :                         if (ctx->pipe == INVALID_HANDLE_VALUE) {
     153             :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Failed to create named pipe %s: %d\n", szNamedPipe, GetLastError()));
     154             :                                 e = GF_IO_ERR;
     155             :                         }
     156             :                         else {
     157             :                                 GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[PipeOut] Waiting for client connection for %s, blocking\n", szNamedPipe));
     158             :                                 if (!ConnectNamedPipe(ctx->pipe, NULL) && (GetLastError() != ERROR_PIPE_CONNECTED)) {
     159             :                                         GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Failed to connect named pipe %s: %d\n", szNamedPipe, GetLastError()));
     160             :                                         e = GF_IO_ERR;
     161             :                                         CloseHandle(ctx->pipe);
     162             :                                         ctx->pipe = INVALID_HANDLE_VALUE;
     163             :                                 }
     164             :                                 else {
     165             :                                         ctx->owns_pipe = GF_TRUE;
     166             :                                 }
     167             :                         }
     168             :                 }
     169             :         }
     170             :         else {
     171             :                 ctx->pipe = CreateFile(szNamedPipe, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
     172             :                 if (ctx->pipe == INVALID_HANDLE_VALUE) {
     173             :                         GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Failed to open %s: %d\n", szNamedPipe, GetLastError()));
     174             :                         e = GF_URL_ERROR;
     175             :                 }
     176             :         }
     177             : 
     178             : #else
     179           8 :         if (ctx->fd>=0) close(ctx->fd);
     180           8 :         ctx->fd = -1;
     181             : 
     182           8 :         if (!gf_file_exists(szFinalName) && ctx->mkp) {
     183             : #ifdef GPAC_CONFIG_DARWIN
     184             :                 mknod(szFinalName, S_IFIFO | 0666, 0);
     185             : #else
     186           1 :                 mkfifo(szFinalName, 0666);
     187             : #endif
     188           1 :                 ctx->owns_pipe = GF_TRUE;
     189             :         }
     190             : 
     191           8 :         ctx->fd = open(szFinalName, O_WRONLY );
     192             : 
     193           8 :         if (ctx->fd<0) {
     194           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Cannot open output pipe %s: %s\n", ctx->szFileName, gf_errno_str(errno)));
     195           0 :                 e = ctx->owns_pipe ? GF_IO_ERR : GF_URL_ERROR;
     196             :         }
     197             : #endif
     198             :         if (e) {
     199             :                 return e;
     200             :         }
     201             :         strncpy(ctx->szFileName, szFinalName, GF_MAX_PATH-1);
     202           8 :         ctx->szFileName[GF_MAX_PATH-1] = 0;
     203             :         return GF_OK;
     204             : }
     205             : 
     206           8 : static GF_Err pipeout_setup_file(GF_PipeOutCtx *ctx, Bool explicit_overwrite)
     207             : {
     208             :         const GF_PropertyValue *p;
     209           8 :         p = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_OUTPATH);
     210           8 :         if (p && p->value.string) {
     211           0 :                 return pipeout_open_close(ctx, p->value.string, NULL, 0, explicit_overwrite);
     212           8 :         } else if (ctx->dynext) {
     213           0 :                 p = gf_filter_pid_get_property(ctx->pid, GF_PROP_PCK_FILENUM);
     214           0 :                 if (!p) {
     215           0 :                         p = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_FILE_EXT);
     216           0 :                         if (p && p->value.string) {
     217           0 :                                 return pipeout_open_close(ctx, ctx->dst, p->value.string, 0, explicit_overwrite);
     218             :                         }
     219             :                 }
     220             :         } else {
     221           8 :                 return pipeout_open_close(ctx, ctx->dst, NULL, 0, explicit_overwrite);
     222             :         }
     223             :         return GF_BAD_PARAM;
     224             : }
     225           8 : static GF_Err pipeout_configure_pid(GF_Filter *filter, GF_FilterPid *pid, Bool is_remove)
     226             : {
     227             :         const GF_PropertyValue *p;
     228           8 :         GF_PipeOutCtx *ctx = (GF_PipeOutCtx *) gf_filter_get_udta(filter);
     229           8 :         if (is_remove) {
     230           0 :                 ctx->pid = NULL;
     231           0 :                 pipeout_open_close(ctx, NULL, NULL, 0, GF_FALSE);
     232           0 :                 return GF_OK;
     233             :         }
     234           8 :         gf_filter_pid_check_caps(pid);
     235             : 
     236           8 :         if (!ctx->pid) {
     237             :                 GF_FilterEvent evt;
     238           8 :                 gf_filter_pid_init_play_event(pid, &evt, ctx->start, ctx->speed, "PipeOut");
     239           8 :                 gf_filter_pid_send_event(pid, &evt);
     240             :         }
     241           8 :         ctx->pid = pid;
     242             : 
     243           8 :         p = gf_filter_pid_get_property(pid, GF_PROP_PID_DISABLE_PROGRESSIVE);
     244           8 :         if (p && p->value.uint) {
     245           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Block patching is not supported by pipe output\n"));
     246             :                 return GF_NOT_SUPPORTED;
     247             :         }
     248             :         return GF_OK;
     249             : }
     250             : 
     251           8 : static GF_Err pipeout_initialize(GF_Filter *filter)
     252             : {
     253             :         char *ext;
     254           8 :         GF_PipeOutCtx *ctx = (GF_PipeOutCtx *) gf_filter_get_udta(filter);
     255             : 
     256           8 :         if (!ctx || !ctx->dst) return GF_OK;
     257             : 
     258           8 :         if (strnicmp(ctx->dst, "pipe://", 7) && strstr(ctx->dst, "://"))  {
     259           0 :                 gf_filter_setup_failure(filter, GF_NOT_SUPPORTED);
     260           0 :                 return GF_NOT_SUPPORTED;
     261             :         }
     262           8 :         if (ctx->dynext) return GF_OK;
     263             : 
     264           8 :         if (ctx->ext) ext = ctx->ext;
     265             :         else {
     266           0 :                 ext = gf_file_ext_start(ctx->dst);
     267           0 :                 if (ext) ext++;
     268             :         }
     269             : 
     270             : #ifdef WIN32
     271             :         ctx->pipe = INVALID_HANDLE_VALUE;
     272             : #else
     273           8 :         ctx->fd = -1;
     274             : #endif
     275           8 :         if (!ext && !ctx->mime) {
     276           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] No extension provided nor mime type for output file %s, cannot infer format\n", ctx->dst));
     277             :                 return GF_NOT_SUPPORTED;
     278             :         }
     279             :         //static cap, streamtype = file
     280           8 :         ctx->in_caps[0].code = GF_PROP_PID_STREAM_TYPE;
     281           8 :         ctx->in_caps[0].val = PROP_UINT(GF_STREAM_FILE);
     282           8 :         ctx->in_caps[0].flags = GF_CAPS_INPUT_STATIC;
     283             : 
     284           8 :         if (ctx->mime) {
     285           0 :                 ctx->in_caps[1].code = GF_PROP_PID_MIME;
     286           0 :                 ctx->in_caps[1].val = PROP_NAME( ctx->mime );
     287           0 :                 ctx->in_caps[1].flags = GF_CAPS_INPUT;
     288             :         } else {
     289           8 :                 strncpy(ctx->szExt, ext, 9);
     290           8 :                 ctx->szExt[9] = 0;
     291           8 :                 strlwr(ctx->szExt);
     292           8 :                 ctx->in_caps[1].code = GF_PROP_PID_FILE_EXT;
     293           8 :                 ctx->in_caps[1].val = PROP_NAME( ctx->szExt );
     294           8 :                 ctx->in_caps[1].flags = GF_CAPS_INPUT;
     295             :         }
     296           8 :         gf_filter_override_caps(filter, ctx->in_caps, 2);
     297           8 :         return GF_OK;
     298             : }
     299             : 
     300           8 : static void pipeout_finalize(GF_Filter *filter)
     301             : {
     302           8 :         GF_PipeOutCtx *ctx = (GF_PipeOutCtx *) gf_filter_get_udta(filter);
     303           8 :         pipeout_open_close(ctx, NULL, NULL, 0, GF_FALSE);
     304             : 
     305           8 :         if (ctx->owns_pipe)
     306           1 :                 gf_file_delete(ctx->szFileName);
     307           8 : }
     308             : 
     309        1080 : static GF_Err pipeout_process(GF_Filter *filter)
     310             : {
     311             :         GF_FilterPacket *pck;
     312             :         const GF_PropertyValue *fname, *p;
     313             :         Bool start, end;
     314             :         const char *pck_data;
     315             :         u32 pck_size;
     316             :         s32 nb_write;
     317        1080 :         GF_PipeOutCtx *ctx = (GF_PipeOutCtx *) gf_filter_get_udta(filter);
     318             : 
     319        1080 :         pck = gf_filter_pid_get_packet(ctx->pid);
     320        1080 :         if (!pck) {
     321           8 :                 if (gf_filter_pid_is_eos(ctx->pid)) {
     322           8 :                         pipeout_open_close(ctx, NULL, NULL, 0, GF_FALSE);
     323           8 :                         return GF_EOS;
     324             :                 }
     325             :                 return GF_OK;
     326             :         }
     327             : 
     328        1072 :         gf_filter_pck_get_framing(pck, &start, &end);
     329             : 
     330        1072 :         if (start) {
     331             :                 const GF_PropertyValue *fext, *fnum;
     332             : 
     333             :                 Bool explicit_overwrite = GF_FALSE;
     334             :                 const char *name = NULL;
     335             :                 fname = fext = NULL;
     336             :                 //file num increased per packet, open new file
     337           8 :                 fnum = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENUM);
     338           8 :                 if (fnum) {
     339           0 :                         fname = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_OUTPATH);
     340           0 :                         fext = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_FILE_EXT);
     341           0 :                         if (!fname) name = ctx->dst;
     342             :                 }
     343             :                 //filename change at packet start, open new file
     344           8 :                 if (!fname) fname = gf_filter_pck_get_property(pck, GF_PROP_PCK_FILENAME);
     345           8 :                 if (!fname) fname = gf_filter_pck_get_property(pck, GF_PROP_PID_OUTPATH);
     346           8 :                 if (!fext) fext = gf_filter_pck_get_property(pck, GF_PROP_PID_FILE_EXT);
     347           8 :                 if (fname) name = fname->value.string;
     348             : 
     349           8 :                 if (end && gf_filter_pck_get_seek_flag(pck))
     350             :                         explicit_overwrite = GF_TRUE;
     351             : 
     352           8 :                 if (name) {
     353           0 :                         pipeout_open_close(ctx, name, fext ? fext->value.string : NULL, fnum ? fnum->value.uint : 0, explicit_overwrite);
     354           8 :                 } else if (
     355             : #ifdef WIN32
     356             :                         ctx->pipe==INVALID_HANDLE_VALUE
     357             : #else
     358           8 :                         ctx->fd<0
     359             : #endif
     360             :                         ) {
     361           8 :                         GF_Err e = pipeout_setup_file(ctx, explicit_overwrite);
     362           8 :                         if (e) {
     363           0 :                                 gf_filter_setup_failure(filter, e);
     364           0 :                                 return e;
     365             :                         }
     366             :                 }
     367             :         }
     368             : 
     369        1072 :         pck_data = gf_filter_pck_get_data(pck, &pck_size);
     370        1072 :         if (
     371             : #ifdef WIN32
     372             :                 ctx->pipe != INVALID_HANDLE_VALUE
     373             : #else
     374        1072 :                 ctx->fd>=0
     375             : #endif
     376             :                 ) {
     377        1072 :                 GF_FilterFrameInterface *hwf = gf_filter_pck_get_frame_interface(pck);
     378        1072 :                 if (pck_data) {
     379             : #ifdef WIN32
     380             :                         if (! WriteFile(ctx->pipe, pck_data, pck_size, (LPDWORD) &nb_write, NULL)) {
     381             :                                 nb_write = 0;
     382             :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Write error, wrote %d bytes but had %u to write: error %d\n", nb_write, pck_size, GetLastError() ));
     383             :                         }
     384             : #else
     385        1072 :                         nb_write = (s32) write(ctx->fd, pck_data, pck_size);
     386        1072 :                         if (nb_write != pck_size) {
     387           0 :                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Write error, wrote %d bytes but had %u to write: %s\n", nb_write, pck_size, gf_errno_str(errno)));
     388             :                         }
     389             : #endif
     390           0 :                 } else if (hwf) {
     391             :                         u32 w, h, stride, stride_uv, pf;
     392             :                         u32 nb_planes, uv_height;
     393           0 :                         p = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_WIDTH);
     394           0 :                         w = p ? p->value.uint : 0;
     395           0 :                         p = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_HEIGHT);
     396           0 :                         h = p ? p->value.uint : 0;
     397           0 :                         p = gf_filter_pid_get_property(ctx->pid, GF_PROP_PID_PIXFMT);
     398           0 :                         pf = p ? p->value.uint : 0;
     399             : 
     400             :                         //get stride/stride_uv with no padding
     401           0 :                         stride = stride_uv = 0;
     402           0 :                         if (gf_pixel_get_size_info(pf, w, h, NULL, &stride, &stride_uv, &nb_planes, &uv_height) == GF_TRUE) {
     403             :                                 u32 i;
     404           0 :                                 for (i=0; i<nb_planes; i++) {
     405             :                                         u32 j, write_h, lsize;
     406             :                                         const u8 *out_ptr;
     407           0 :                                         u32 out_stride = i ? stride_uv : stride;
     408           0 :                                         GF_Err e = hwf->get_plane(hwf, i, &out_ptr, &out_stride);
     409           0 :                                         if (e) {
     410           0 :                                                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Failed to fetch plane data from hardware frame, cannot write\n"));
     411           0 :                                                 break;
     412             :                                         }
     413           0 :                                         if (i) {
     414           0 :                                                 write_h = uv_height;
     415           0 :                                                 lsize = stride_uv;
     416             :                                         } else {
     417             :                                                 write_h = h;
     418           0 :                                                 lsize = stride;
     419             :                                         }
     420             : 
     421           0 :                                         for (j=0; j<write_h; j++) {
     422             : #ifdef WIN32
     423             :                                                 if (!WriteFile(ctx->pipe, out_ptr, lsize, (LPDWORD) &nb_write, NULL)) {
     424             :                                                         nb_write = 0;
     425             :                                                         GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Write error, wrote %d bytes but had %u to write: %d\n", nb_write, pck_size, GetLastError()));
     426             :                                                 }
     427             : #else
     428           0 :                                                 nb_write = (s32) write(ctx->fd, out_ptr, lsize);
     429           0 :                                                 if (nb_write != lsize) {
     430           0 :                                                         GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Write error, wrote %d bytes but had %u to write: %s\n", nb_write, lsize, gf_errno_str(errno)));
     431             :                                                 }
     432             : #endif
     433           0 :                                                 out_ptr += out_stride;
     434             :                                         }
     435             :                                 }
     436             :                         }
     437             :                 } else {
     438           0 :                         GF_LOG(GF_LOG_WARNING, GF_LOG_MMIO, ("[PipeOut] No data associated with packet, cannot write\n"));
     439             :                 }
     440             :         } else {
     441           0 :                 GF_LOG(GF_LOG_ERROR, GF_LOG_MMIO, ("[PipeOut] Output file handle is not opened, discarding %d bytes\n", pck_size));
     442             :         }
     443        1072 :         gf_filter_pid_drop_packet(ctx->pid);
     444        1072 :         if (end) {
     445           4 :                 pipeout_open_close(ctx, NULL, NULL, 0, GF_FALSE);
     446             :         }
     447             :         return GF_OK;
     448             : }
     449             : 
     450        2198 : static GF_FilterProbeScore pipeout_probe_url(const char *url, const char *mime)
     451             : {
     452        2198 :         if (!strnicmp(url, "pipe://", 7)) return GF_FPROBE_SUPPORTED;
     453        2190 :         if (!strnicmp(url, "pipe:", 5)) return GF_FPROBE_SUPPORTED;
     454        2190 :         return GF_FPROBE_NOT_SUPPORTED;
     455             : }
     456             : 
     457             : 
     458             : #define OFFS(_n)        #_n, offsetof(GF_PipeOutCtx, _n)
     459             : 
     460             : static const GF_FilterArgs PipeOutArgs[] =
     461             : {
     462             :         { OFFS(dst), "name of destination pipe", GF_PROP_NAME, NULL, NULL, 0},
     463             :         { OFFS(ext), "indicate file extension of pipe data", GF_PROP_STRING, NULL, NULL, 0},
     464             :         { OFFS(mime), "indicate mime type of pipe data", GF_PROP_STRING, NULL, NULL, 0},
     465             :         { OFFS(dynext), "indicate the file extension is set by filter chain, not dst", GF_PROP_BOOL, "false", NULL, GF_FS_ARG_HINT_ADVANCED},
     466             :         { OFFS(start), "set playback start offset. Negative value means percent of media duration with -1 equal to duration", GF_PROP_DOUBLE, "0.0", NULL, 0},
     467             :         { OFFS(speed), "set playback speed. If speed is negative and start is 0, start is set to -1", GF_PROP_DOUBLE, "1.0", NULL, 0},
     468             :         { OFFS(mkp), "create pipe if not found - see filter help", GF_PROP_BOOL, "false", NULL, 0 },
     469             :         { OFFS(block_size), "buffer size used to write to pipe, windows only", GF_PROP_UINT, "5000", NULL, GF_FS_ARG_HINT_ADVANCED },
     470             :         {0}
     471             : };
     472             : 
     473             : static const GF_FilterCapability PipeOutCaps[] =
     474             : {
     475             :         CAP_UINT(GF_CAPS_INPUT,GF_PROP_PID_STREAM_TYPE, GF_STREAM_FILE),
     476             :         CAP_STRING(GF_CAPS_INPUT,GF_PROP_PID_FILE_EXT, "*"),
     477             :         CAP_STRING(GF_CAPS_INPUT,GF_PROP_PID_MIME, "*"),
     478             : };
     479             : 
     480             : 
     481             : GF_FilterRegister PipeOutRegister = {
     482             :         .name = "pout",
     483             :         GF_FS_SET_DESCRIPTION("pipe output")
     484             :         GF_FS_SET_HELP("This filter handles generic output pipes (mono-directional) in blocking mode only.\n"\
     485             :                 "Warning: Output pipes do not currently support non blocking mode.\n"\
     486             :                 "The associated protocol scheme is `pipe://` when loaded as a generic output (eg, -o `pipe://URL` where URL is a relative or absolute pipe name).\n"\
     487             :                 "Data format of the pipe **shall** be specified using extension (either in filename or through [-ext]() option) or MIME type through [-mime]()\n"\
     488             :                 "The pipe name indicated in [-dst]() can use template mechanisms from gpac, e.g. `dst=pipe_$ServiceID$`\n"\
     489             :                 "\n"\
     490             :                 "On Windows hosts, the default pipe prefix is `\\\\.\\pipe\\gpac\\` if no prefix is set \n"\
     491             :                 "EX dst=mypipe resolves in \\\\.\\pipe\\gpac\\mypipe\n"\
     492             :                 "EX dst=\\\\.\\pipe\\myapp\\mypipe resolves in \\\\.\\pipe\\myapp\\mypipe\n"
     493             :                 "Any destination name starting with `\\\\` is used as is, with `\\` translated in `/`\n"\
     494             :                 "\n"\
     495             :                 "The pipe input can create the pipe if not found using [-mkp](). On windows hosts, this will create a pipe server.\n"\
     496             :                 "On non windows hosts, the created pipe will delete the pipe file upon filter destruction."\
     497             :         "")
     498             :         .private_size = sizeof(GF_PipeOutCtx),
     499             :         .args = PipeOutArgs,
     500             :         SETCAPS(PipeOutCaps),
     501             :         .probe_url = pipeout_probe_url,
     502             :         .initialize = pipeout_initialize,
     503             :         .finalize = pipeout_finalize,
     504             :         .configure_pid = pipeout_configure_pid,
     505             :         .process = pipeout_process
     506             : };
     507             : 
     508             : 
     509        2877 : const GF_FilterRegister *pipeout_register(GF_FilterSession *session)
     510             : {
     511        2877 :         return &PipeOutRegister;
     512             : }
     513             : 

Generated by: LCOV version 1.13