ubuntuusers.de

Videopakete empfangen und in eine Datei schreiben (in C)

Status: Gelöst | Ubuntu-Version: Nicht spezifiziert
Antworten |

Njutik

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo Leute!

Ich habe folgende Situation. Es soll ein Streaming Szenario implementiert werden. Als Server verwende ich den LIVE555MediaServer (www.live555.com), als Client ein selbstgeschriebenes Programm in C. Der Client fordert beim Server ein Video an, der Server streamt das Video zu dem Client. Bis jetzt habe ich das so gemacht, dass ich im Client-Programm, also im C-Code den VLC aufgerufen habe, der eine Stream-Anforderung an den Server geschickt, eine VLC Media Player Instanz aufgemacht hat und den empfangenen Stream (Audio/Video) dort abgespielt hat. Der Nachteil an dieser Lösung ist, dass das gestreamte Video nicht auf den Client-PC erhalten bleibt. Nach dem Ende des Streamings kann ich mir das Video nicht einfach so nochmal anschauen. Wenn der Nutzer also das Video noch mal sehen will, muss wieder das Client-Programm gestartet werden, in dem der VLC aufgerufen wird, Videoanfrage an den Server verschickt und der Stream empfangen und ausgegeben wird.

Als nächsten Schritt möchte ich in meinem Client-Programm eine Änderung vornehmen, die dafür sorgt, dass die empfangenen Videopakete in eine separate Datei gespeichert werden. Da dies mit dem VLC-Code im Programm scheinbar nicht geht, habe ich mir eine Art Gateway gebastelt, das zwischen dem Server und dem Clientprogram angesiedelt ist. Weder Server noch Client sollen von diesem Gateway etwas merken. Also tut das Gateway für den Client so, als wäre es der Server und aus der Sicht des Servers ist das Gateway ein Client. Ergebnis ist, dass der Client und der Server nur mit dem Gateway kommunizieren. Gateway empfängt alle Nachrichten des Client und leitet sie an den Server weiter. Der Server antwortet darauf und das Gateway empfängt wiederum die Antworten und leitet sie an den Client weiter, wo die Nachrichten des Servers vom VLC verarbeitet werden. Zusätzlich speichert das Gateway die empfangenen Videopakete vom Server an den Client in eine Datei, bevor diese Pakete tatsächlich an den Client geschickt werden.

Und jetzt kommt mein eigentliches Problem. Das Gateway speichert zwar alle ankommenden Pakete in eine Datei, aber wenn ich dann diese Datei abspielen will, sehe ich nur Bruchstücke (siehe Bild im Anhang). Gleichzeitig kommen die gleichen Pakete in guter Form beim VLC an und werden als gutes Bild ausgegeben. So wie man es sich eigentlich vorstellt.

Beim Schreiben der Pakete in eine Datei muss ich irgendwas falsch machen. Interessant ist, dass der obere Teil des Bildes ganz ok ist, aber der untere Teil dann um so schlechter. Es sieht fast so aus, als würde dann ein bestimmtes Paket einfach kopiert werden, bis das Bild voll ist.

Hier sind die relevanten Codeabschnitte, wo die ankommenden Daten in eine Datei gespeichert werden:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
#define MAXSTRING 1500

/*--------in der main()-Funktion----------------*/
char recvBytes[MAXSTRING];
int recvBytes;

FILE *vid;
char *filename = "video.mpg";

//printf("RTP1 Paket vom Server\n");
if((recvBytes = recvfrom(RTP1Sock, recvBuffer, MAXSTRING, 0, (struct sockaddr *)&FromAddr, &fromAddrLen)) < 0)
{
DieWithError("Failed to receive an RTP1 Paket");
}
recvBuffer[recvBytes] = '\0';
fwrite(&recvBuffer, sizeof(char), recvBytes, vid);

Hat jemand eine Idee, woran das liegen könnte? Ich freue mich über alle Anregungen, Hinweise, gefundenen Fehler usw. Ich suche schon seit einigen Tagen nur nach dieser Lösung. Es wäre super, wenn mir jemand weiterhelfen könnte.

Liebe Grüße

Anna

Bilder

snafu1

Avatar von snafu1

Anmeldungsdatum:
5. September 2007

Beiträge: 2133

Wohnort: Gelsenkirchen

Ich hab ja jetzt nicht sooo viel Ahnung von C, aber müsste die terminierende Null nicht auf recvBytes + 1 stehen? Keine Ahnung, ob dies der Fehler ist.

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo snafu1! Danke für Deine Antwort. Dein Hinweis ist mir auch aufgefallen, ich habe es geändert, aber der Fehler bleibt leider. ☹ Daran scheint es also nicht zu liegen.

liebe Grüße

Anna

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4687

Wohnort: Berlin

@Njutik: Warum schreibst Du denn da überhaupt ein Nullbyte in den Puffer? Hat die gespeicherte Datei die richtige Grösse? Steckt der Code in einer Schleife? recvfrom() muss laut Doku nicht alle Bytes bei einem Aufruf liefern.

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo Marc 'BlackJack' Rintsch!

Danke für die Antwort. Die Null am Ende des Puffers ist eigentlich auch egal. Aber auch da hatte sich nachdem Weglassen der Null nichts geändert. Der Code steckt in der Schleife, das passt schon.

Nach langem Hin und Her habe ich jetzt endlich eine Art von Lösung gefunden. Mir ist aufgefallen, dass einige MPEG2-Dateien komplett aufgenommen und weitestgehend fehlerfrei abgespielt wurden. Es gab lediglich ein paar weiße Streifen am Bildrand. MPEG1-Dateien konnten jedoch überhaupt nicht vernünftig abgespielt werden. Nur so, wie das Bild zeigte. Nachdem ich die "erfolgreichen" MPEG2-Dateien mir mit mediainfo genauer angeschaut habe, sah ich, dass bei allen diesen Dateien als Scan Type "Interlaced" angegeben war, bei den "schlechten" Dateien jedoch immer "progressive" stand. Ich habe das im Avidemux geändert und dabei als Videocodec DVD (lavc) und als Audiocodec MP2 (TwoLame) genommen. Zu beachten ist noch, dass bei Video die Bitrate auf PAL oder auf NTSC zu setzen ist. In der Konfiguration des Video-Codec muss man dann bei "Interlacing" TFF (bei PAL) oder BFF (bei NTSC) angeben. Bei der Audio-Kopie muss man dann auf "Filter" gehen und dort "resammpling 48000 Hz" aktivieren. Dann als Format MPEG-PS auswählen und abspeichern. Wenn ich das Video übertrage, speichere und abspiele sieht es, wie gesagt, abgesehen von den gelegentlichen kleinen weissen Streifen gut aus. Bei Trickfilmen gab es überhaupt keine Probleme.

Ich weiss nicht, warum das Problem bei diesem Interlaced-Progressive Zeug war, Hauptsache es funktioniert jetzt.

Vielen herzlichen Dank an alle, die mir geschrieben haben.

Liebe Grüße

Anna

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4687

Wohnort: Berlin

@Njutik: Ich denke damit hast Du das Problem nicht grundsätzlich gelöst, sondern nur Einstellungen für das Video gefunden, bei denen die gleichen Fehler nicht so stark auffallen. Dein Mitschneiden verändert offensichtlich die Daten. Entweder fügst Du Daten hinzu, lässt welche weg, oder Du veränderst etwas.

Du hast meine Frage nach der Dateigrösse nicht beantwortet. Du solltest Dir einfach mal anschauen wo sich die gesendete und die empfangene und gespeicherte Datei unterscheiden.

Sind das UDP-Pakete? Wenn ja, dann müssen da ja zum Beispiel noch Zusatzinformationen drin sein, damit der Empfänger die wieder in die richtige Reihenfolge bekommt. Wenn Du dann einfach die ganzen Pakete nacheinander in eine Datei schreibst, enthalten die a) immer einen kleinen Anteil "Datenmüll", der nicht zum Film gehört und sie können b) in falscher Reihenfolge gespeichert sein. Beides führt beim Abspielen zu Bildfehlern.

Njutik

(Themenstarter)

Anmeldungsdatum:
29. Januar 2009

Beiträge: 52

Hallo Marc 'BlackJack' Rintsch!

Nach Deinem Post komme ich doch ins Grübeln, ob ich mich zu früh gefreut habe. Habe mir gerade die Originaldatei und die empfangene Datei angeschaut und zwar Videos, die wie ursprünglich im "progressive" statt im "Interlaced" Modus waren. Ich dachte, dass die recvfrom() Funktion die empfangenen Pakete intern schon so weit aufbereitet, dass beim Nutzer lediglich die Payload ankommt, die auch ursprünglich vom Sender verschickt wurde. Nach Deiner Meldung dachte ich, dass da vielleicht doch noch der Header drin ist. Ich habe mir bei der Programmausführung die Anzahl der empfangenen Bytes anzeigen lassen und diese dann mit der Bytesanzahl verglichen, die bei wireshark bei den empfangenen Paketen angegeben werden. Und die Anzahl der vom Programm empfangenen Bytes stimmt mit der Anzahl der Nutzbytes in wireshark überein. Im Hex-Editor gibt es allerdings einen geringen Unterschied zwischen der Originaldatei und der aufgenommenen Datei an einigen Stellen. Allerdings weiss ich nicht, was mir diese Differenzen sagen können. Du hast Recht, die eigentlichen Videopakete werden mit UDP übertragen. Sind da bei dieser unzuverlässigen Art der Übertragung nicht einige Differenzen normal? Die Informationen, die Du meinst, die für die richtige Reihenfolge bei den Paketen sorgen sollen etc. müssten doch eigentlich im Header sein, oder? Und der scheint (laut dem Vergleich der empfangenen Bytesanzahl mit der Anzahl der Nutzbytes bei wireshark) schon ellimiert zu sein.

Ich habe auch die Größen der Dateien verglichen. Die Originaldatei ist 5.48 MiB groß und die aufgenommene Datei 4.58 MiB groß.

Ich werde weiterhin versuchen, den eigentlichen Grund für das Problem zu finden. Wenn Dir oder sonst irgendjemandem dazu noch irgendwelche Fragen, Anregungen, Bemerkungen, Hinweise usw. auffallen, sagt mir bitte bescheid!

Liebe Grüße

Anna

Marc_BlackJack_Rintsch Team-Icon

Ehemalige
Avatar von Marc_BlackJack_Rintsch

Anmeldungsdatum:
16. Juni 2006

Beiträge: 4687

Wohnort: Berlin

@Njutik: Von welchem Header redest Du denn jetzt? Der von der Transportschicht ist natürlich schon weg, aber zu den Nutzdaten gehört ein Header von RTP, denn der Videoplayer muss ja wissen welches Paket er da gerade vor sich hat, um die in die richtige Reihenfolge zu bekommen.

http://en.wikipedia.org/wiki/Real-time_Transport_Protocol#Packet_header

Die Pakete einfach in eine Datei "dumpen" ergibt keinen Film in einem "normalen" Format.

Antworten |