Gambas-it

Gambas3 => Programmazione => Topic aperto da: allegfede - 13 Settembre 2019, 12:01:20

Titolo: GSTREAMER errore troppi file aperti
Inserito da: allegfede - 13 Settembre 2019, 12:01:20
Salve a tutti, ho fatto un programma che registra in continuazione da una sorgente audio, comprime l'audio e ne fa pezzetti da un'ora per 90 giorni (poi cancello i file piu' vecchi).
Normalmente funziona per diverse settimane con un errore di "troppi file aperti".

Cercando su internet con gstreamer AND "too many files open" e' venuto fuori questo thread:
http://gstreamer-devel.966125.n4.nabble.com/Too-many-files-open-issue-td4687242.html

che mi sembra attinente.

Sembrerebbe che la semplice interruzione della pipeline, la sua distruzione e la sua riapertura NON siano sufficienti a FERMARE la registrazione.

Si deve inviare un EOS alla pipeline ed il codice C proposto e' questo:
Codice: [Seleziona]
void worker(GstElement *pipeline) {
    gst_element_send_event(pipeline, gst_event_new_eos());
}

void stopListening() {
    boost::thread *th = new boost::thread(worker,pipeline);
}

nel mio programma, che trovate qui':
https://sourceforge.net/projects/prsose/files/tools/PRS_recorder-0.0.10.tar.gz/

il codice che si occupa di chiudere la pipeline e generare un nuovo file e' questo:
Codice: [Seleziona]
Public Sub PipeLine(command As String)
Dim Destinazione As New String[]
Dim Risultato As String
Dim clienti As String[]
Dim I As Integer
 
  Select Case command
    Case "start"
      InitCaptureSystem
     
      InitSink
     
      muxer.LinkTo(sink)
     
      Try pl.Play
      If Error Then
        Message.Warning("Error starting gstreamer graph. Is Jack Audio server runnig?", "ok")
        ToggleButton_RecStop.Value = False
      Endif
     
      'riconnette al volo le sorgenti (se la cosa va gestita dall'applicazione e non dal sistema
      If AutoReconnectSource = True Then
        'non so perche' ma i client mi cambiano nome in modo progressivo .. quindi devo trovare quelli al momento validi per il mio programma
        'quindi scansiono i clienti di jack attivi (ho dato il play alla pipeline quindi c'e' anche il recorder) e mi trovo quelli con il nome
        'simile a quello che ho settato io in init_capture_system .... ovver "client_name" qualcosa
        Shell "jack_lsp" To Risultato
        clienti = Split(Risultato, gb.CrLf)
        For i = 0 To clienti.Count - 1
          If clienti[i] Like ("*" & clientname & "*") Then
            Destinazione.Add(clienti[i], Destinazione.Count)
          Endif
        Next
       
        'a questo punto dovrei avere uno o piu' sink del mio programma che ricevono l'audio dalla sorgente che ho indicato
        Shell "jack_connect " & Replace(FirstJackSource, " ", "\\ ") & " " & Destinazione[0]
        If StereoSource = True Then
          Shell "jack_connect " & GetNextOf(FirstJackSource) & " " & Destinazione[1]
        Endif
       
      Endif
     
      Timer_RecordClock.Start
    Case "stop"
      Try pl.stop
     
      Try Copy User.home & "/" & ClientName & ".ogg" To RealName
     
      Try pl.Close
     
      CheckForFilesToDelete
     
      Timer_RecordClock.Stop 
  End Select
 
End

mentre l'inizializzazione della pipeline si fa cosi' (nel mio programma):
Codice: [Seleziona]
Public Sub InitCaptureSystem()

  Try pl.Stop
  Try pl.close

  Try Recorder_Client.close
  Try audioformat.close
  Try audio_converter.close
  Try lev.close
  Try muxer.close
  Try que1.close
  Try que2.close
  Try que3.close
 
'in teoria dovrebbe funzionare:
'gst-launch-1.0 jackaudiosrc connect=0 client-name="test" ! audioconvert ! avenc_aac ! mp4mux ! filesink location=aac_audio.mp4

  pl = New MediaPipeline As "PipeLine"

  'dico a gstreamer che la sorgente audio e' una sorgente di jack-server
  Recorder_Client = New MediaControl(pl, "jackaudiosrc")
  Recorder_Client["client-name"] = ClientName

  Recorder_Client["connect"] = 0

  audioformat = New MediaFilter(pl, "audio/x-raw,channels=2")
  audio_converter = New MediaControl(pl, "audioconvert")
 
  'qui decidiamo il tipo di encoder
  Select Case encType
    Case "vorbis"
      encoder = New MediaControl(pl, "vorbisenc")
      encoder["name"] = "enc"
      encoder["quality"] = -0.1
    Case "opus"
      encoder = New MediaControl(pl, "opusenc") 'opusenc name=enc bitrate=24000 bitrate-type="vbr"
      encoder["name"] = "enc"
      encoder["bitrate"] = 24000
      encoder["bitrate-type"] = 2 '0=cbr 1=vbr  2=CONSTRAINED_VBR .. che penso sia vbr entro un certo bitrate
    Case "mp3"
      encoder = New MediaControl(pl, "lamemp3enc") 'opusenc name=enc bitrate=24000 bitrate-type="vbr"
      encoder["name"] = "enc"
      encoder["bitrate"] = 32
      encoder["cbr"] = False 'esempi lamemp3enc target=bitrate cbr=true bitrate=192 | lamemp3enc target=quality quality=0
  End Select
 
  lev = New MediaControl(pl, "level")
  lev["message"] = True

  muxer = New MediaControl(pl, "oggmux")
  que1 = New MediaControl(pl, "queue")
  que2 = New MediaControl(pl, "queue")
  que3 = New MediaControl(pl, "queue")

' Parte audio SENZA LIVELLI AUDIO:
  Recorder_Client.LinkTo(audioformat)
  audioformat.LinkTo(audio_converter)
  'audio_converter.LinkTo(encoder)
    'per cercare di estrarre i livelli dell'audio in ingresso invece:
    audio_converter.LinkTo(lev)
    lev.LinkTo(encoder)
  '
   encoder.LinkTo(muxer)
 
End


Public Sub InitSink()
'Dim sink As MediaControl

  Try sink.close

  'se si vuole registrare su file;
  sink = New MediaControl(pl, "filesink")
  'sarebbe da rendere parametrica la path
  sink["location"] = User.Home & "/" & ClientName & ".ogg"
  RealName = RecordingRoot & "/" & ClientName & "_" & Format(Now, "yyyy-mm-dd_hh-nn-ss") & ".ogg"
End

Da super scarsone di C, come faccio a mandare questo fatidico messaggio di EOS alla pipeline?

PS: in allegato l'ultima versione con qualche piccola modifica.
Titolo: Re:GSTREAMER errore troppi file aperti
Inserito da: Gianluigi - 13 Settembre 2019, 12:49:42
 :ciao:
Citazione
  Try pl.Stop
  Try pl.close
Se capisco bene, qui vedo una cosa senza senso, se pl fosse una variabile globale ok ma così...

penso che l'errore possa essere questo

 :ciao:
Titolo: Re:GSTREAMER errore troppi file aperti
Inserito da: allegfede - 13 Settembre 2019, 13:19:52
si pl e' una variabile globale ....

nella procedura (che si ripete ogni ora ma che nella prima invocazione NON trovera' nessuna vecchia pipeline) l'idea e' di "distruggere" la vecchia PL e ricrearne un'altra (che viene riferita in piu' parti del codice).

Tu dici che la "new" nella procedura istanzia un oggetto che e' distaccato dal resto a causa dello scope locale? Non penso, di solito in tutti gli esempi con GStreamer si fa cosi'.

Comunque la dichiarazione in testa al codice e' questa:
Codice: [Seleziona]
' Gambas class file
Public pl As MediaPipeline
Public Recorder_Client As MediaControl
Public audio_converter As MediaControl
Public audioformat As MediaControl
Public encoder As MediaControl
Public que1 As MediaControl
Public que2 As MediaControl
Public que3 As MediaControl
Public muxer As MediaControl
Public lev As MediaControl
Public sink As MediaControl

Public ClientName As String
Public RecordingRoot As String
Public Spezzetta As Boolean

'per gestire la riconnessione delle sorgenti dall'interno dell'applicazione.
Public StereoSource As Boolean
Public FirstJackSource As String
Public AutoReconnectSource As Boolean

Public Giorni As Integer

Public RealName As String 

Public encType As String = "vorbis"

.... etc etc ..
Titolo: Re:GSTREAMER errore troppi file aperti
Inserito da: Gianluigi - 13 Settembre 2019, 13:33:56
No scusa sono io che ho capito male e ho scritto una caaavolata.
ieri ho bevuto dell'ottimo marsala stagionato, e non devo averlo ancora smaltito   :rolleyes:

Forse l'unica è chiedere a Minisini, se è possibile che avvenga quello che temi, ma se non c'è un bug credo che usando i metodi Gambas non dovresti avere problemi.

 :ciao:
Titolo: Re:GSTREAMER errore troppi file aperti
Inserito da: allegfede - 13 Settembre 2019, 13:55:51
invidio il marsala di qualita'  :D
Titolo: Re:GSTREAMER errore troppi file aperti
Inserito da: allegfede - 13 Settembre 2019, 19:12:03
in ogni caso, dando un'occhiata qui':
https://fossies.org/linux/gambas/gb.media/src/c_media.c

sembrerebbe che GIA' ORA, fermando una pipeline con il metodo pipeline.stop
si dovrebbe mandare il segnale EOS ....
Codice: [Seleziona]
 1807 void MEDIA_stop_pipeline(CMEDIACONTROL *_object)
 1808 {
 1809     int try;
 1810
 1811     // "It is not allowed to post GST_MESSAGE_EOS when not in the PLAYING state." says the documentation
 1812     if ((THIS->state == GST_STATE_PLAYING) && !THIS->eos)
 1813     {
 1814         try = 0;
 1815         gst_element_send_event(ELEMENT, gst_event_new_eos());
 1816         while (!THIS->eos)
 1817         {
 1818             try++;
 1819             if (try > 25)
 1820             {
 1821                 fprintf(stderr, "gb.media: warning: could not catch end of stream\n");
 1822                 break;
 1823             }
 1824             cb_message(THIS_PIPELINE);
 1825             usleep(10000);
 1826         }
 1827     }
 1828
 1829     MEDIA_set_state(THIS, GST_STATE_READY, TRUE);
 1830     cb_message(THIS_PIPELINE);
 1831 }