baerbelita
01.11.2006, 10:06
Hallo,
ich versuche den Berkeley MPEG-2 Codec so umzubauen, dass er über das Protokoll RTP kodierte Videodaten über das Netzwerk sendet. Hierfür verwende ich die Bibliothek rtplib (www-out.bell-labs.com/project/RTPlib/).
Ich kodiere eine GOP mit einer vorgegebenen, von GOP zu GOP variierenden Bitrate (50 kbps - 10000 kbps) und schreibe die kodierten Daten in eine Liste. Nachem eine GOP kodiert wurde, möchte ich die erzeugten Daten gerne mit der selben Bitrate versenden. Wie kann ich das erreichen? So, wie ich es mir überlegt hatte (s.h. Code), klappt es jedenfalls nicht :(
double hanldeRTP(float byte_rate) {
// ...
while(1) {
// Check whether there is data that hasn't been sent
tmp = readFromEncDataQueue();
if(tmp == NULL) {
// finished
return (double) total_read;
}
//********************* Send the video data ***************************
bytes_read = tmp -> encDataNum;
err = RTPSend(cid, (int32) tsinc, marker, PAYLOAD_TYPE_MPEG_VIDEO,
tmp ->encDataBuffer, tmp -> encDataNum);
if (err != RTP_OK) {
fprintf(stderr, "Packet could not be sent: %s\n", RTPStrError(err));
exit(1);
}
free(tmp);
// ******************* Calculate when to send the next packet **********
total_read += bytes_read;
last_read = bytes_read;
play_time = start_time + (total_read * byte_rate);
// ******************* RTP and RTCP packet handling ********************
/* Handle RTP events and received RTP and RTCP packets until the next
* play time. */
while (gettimeofday(&now_tv, NULL), (now = tv2dbl(now_tv)) < play_time) {
// do other things until we have to send next video data
}
}
}
Die RTP Bibliotheksfunktionen sehen so aus (sorry für den vielen Code).
rtperror RTPSend(context cid, int32 tsinc, int8 marker,
int16 pti, int8 *payload, int len) {
struct iovec payload_vec[1];
payload_vec[0].iov_base = payload;
payload_vec[0].iov_len = len;
return RTPSendVector(cid, tsinc, marker, pti, payload_vec, 1);
}
rtperror RTPSendVector(context cid, int32 tsinc, int8 marker,
int16 pti, struct iovec *payload, int vec_count) {
/* Our packet will be composed of vec_count + 2 buffers:
buffer 0 is the header
buffers 1 .. n-1 are the payload
buffer n is the payload padding */
struct iovec *pktpart;
int pktlen;
int buflen;
struct msghdr the_message;
int errchk, i, data_len, rundelete;
address_holder_t *s, *prevs;
rtperror err;
hl_context *uc;
err = RTPSessionGetHighLevelInfo(cid, (void**)&uc);
if (err != RTP_OK)
/* The cid is bogus */
return err;
if (uc->PreventEntryIntoFlaggingFunctions) {
return errordebug(RTP_CANT_CALL_FUNCTION, "RTPSendVector",
"context %d, cannot be called now",
(int)cid);
}
if(uc->send_addr_list == NULL) {
return errordebug(RTP_BAD_ADDR, "RTPSendVector",
"context %d, no send addresses",
(int)cid);
}
pktlen = vec_count + 2;
pktpart = (struct iovec *) calloc(sizeof(struct iovec), pktlen);
if (pktpart == NULL) {
return errordebug(RTP_CANT_ALLOC_MEM, "RTPSendVector",
"context %d, couldn't allocate iovec",
(int)cid);
}
uc->PreventEntryIntoFlaggingFunctions = TRUE;
data_len = 0;
for (i = 0; i < vec_count; i++) {
pktpart[i+1].iov_base = payload[i].iov_base;
pktpart[i+1].iov_len = payload[i].iov_len;
data_len += payload[i].iov_len;
/* octet count only measures the payload (no extension, no SSRC lists,
etc.) */
}
buflen = _RTP_MAX_PKT_SIZE;
err = RTPBuildRTPHeader(cid, tsinc, marker, pti, FALSE /* ... XXX encrypt */,
data_len, uc->packet_buffer, &buflen);
if (err)
goto cleanup;
pktpart[0].iov_base = uc->packet_buffer;
pktpart[0].iov_len = buflen;
/* Add padding to the payload if necessary */
/* XXX encryption */
pktpart[pktlen-1].iov_base = NULL;
pktpart[pktlen-1].iov_len = 0;
/* XXX do encryption here */
/* Packet is not encrypted. Then it is ready to be sent. */
memset((char*) &the_message, 0, sizeof(the_message));
the_message.msg_name = (caddr_t) NULL;
the_message.msg_namelen = 0;
the_message.msg_iov = pktpart;
the_message.msg_iovlen = pktlen;
s = uc->send_addr_list;
err = RTP_OK;
rundelete = FALSE;
while(s != NULL) {
if(s->deleteflag == FALSE) {
errchk = _sys_sendmsg(s->rtpsocket, (struct msghdr*)
&the_message, 0);
if (errchk < 0) {
err = errordebug(RTP_SOCKET_WRITE_FAILURE, "RTPSendVector",
"context %d could not write to RTP socket",
(int)cid);
if (uc->SendErrorCallBack != NULL) {
uc->SendErrorCallBack(cid,
inet_ntoa(s->address),
ntohs(s->port),
s->ttl);
}
if (s->deleteflag == TRUE) {
rundelete = TRUE;
}
}
} else {
rundelete = TRUE;
}
s = s->next;
}
/* Now, we clean up the send list and remove all that have been deleted.
We know that this needs to be done if rundelete is TRUE */
prevs = NULL;
if(rundelete == TRUE) {
s = uc->send_addr_list;
while(s != NULL) {
if(s->deleteflag == TRUE) {
if(prevs == NULL)
uc->send_addr_list = s->next;
else
prevs->next = s->next;
_sys_close_socket(s->rtpsocket);
_sys_close_socket(s->rtcpsocket);
free(s);
}
prevs = s;
s = s->next;
}
}
cleanup:
free(pktpart);
uc->PreventEntryIntoFlaggingFunctions = FALSE;
return(err);
}
ich versuche den Berkeley MPEG-2 Codec so umzubauen, dass er über das Protokoll RTP kodierte Videodaten über das Netzwerk sendet. Hierfür verwende ich die Bibliothek rtplib (www-out.bell-labs.com/project/RTPlib/).
Ich kodiere eine GOP mit einer vorgegebenen, von GOP zu GOP variierenden Bitrate (50 kbps - 10000 kbps) und schreibe die kodierten Daten in eine Liste. Nachem eine GOP kodiert wurde, möchte ich die erzeugten Daten gerne mit der selben Bitrate versenden. Wie kann ich das erreichen? So, wie ich es mir überlegt hatte (s.h. Code), klappt es jedenfalls nicht :(
double hanldeRTP(float byte_rate) {
// ...
while(1) {
// Check whether there is data that hasn't been sent
tmp = readFromEncDataQueue();
if(tmp == NULL) {
// finished
return (double) total_read;
}
//********************* Send the video data ***************************
bytes_read = tmp -> encDataNum;
err = RTPSend(cid, (int32) tsinc, marker, PAYLOAD_TYPE_MPEG_VIDEO,
tmp ->encDataBuffer, tmp -> encDataNum);
if (err != RTP_OK) {
fprintf(stderr, "Packet could not be sent: %s\n", RTPStrError(err));
exit(1);
}
free(tmp);
// ******************* Calculate when to send the next packet **********
total_read += bytes_read;
last_read = bytes_read;
play_time = start_time + (total_read * byte_rate);
// ******************* RTP and RTCP packet handling ********************
/* Handle RTP events and received RTP and RTCP packets until the next
* play time. */
while (gettimeofday(&now_tv, NULL), (now = tv2dbl(now_tv)) < play_time) {
// do other things until we have to send next video data
}
}
}
Die RTP Bibliotheksfunktionen sehen so aus (sorry für den vielen Code).
rtperror RTPSend(context cid, int32 tsinc, int8 marker,
int16 pti, int8 *payload, int len) {
struct iovec payload_vec[1];
payload_vec[0].iov_base = payload;
payload_vec[0].iov_len = len;
return RTPSendVector(cid, tsinc, marker, pti, payload_vec, 1);
}
rtperror RTPSendVector(context cid, int32 tsinc, int8 marker,
int16 pti, struct iovec *payload, int vec_count) {
/* Our packet will be composed of vec_count + 2 buffers:
buffer 0 is the header
buffers 1 .. n-1 are the payload
buffer n is the payload padding */
struct iovec *pktpart;
int pktlen;
int buflen;
struct msghdr the_message;
int errchk, i, data_len, rundelete;
address_holder_t *s, *prevs;
rtperror err;
hl_context *uc;
err = RTPSessionGetHighLevelInfo(cid, (void**)&uc);
if (err != RTP_OK)
/* The cid is bogus */
return err;
if (uc->PreventEntryIntoFlaggingFunctions) {
return errordebug(RTP_CANT_CALL_FUNCTION, "RTPSendVector",
"context %d, cannot be called now",
(int)cid);
}
if(uc->send_addr_list == NULL) {
return errordebug(RTP_BAD_ADDR, "RTPSendVector",
"context %d, no send addresses",
(int)cid);
}
pktlen = vec_count + 2;
pktpart = (struct iovec *) calloc(sizeof(struct iovec), pktlen);
if (pktpart == NULL) {
return errordebug(RTP_CANT_ALLOC_MEM, "RTPSendVector",
"context %d, couldn't allocate iovec",
(int)cid);
}
uc->PreventEntryIntoFlaggingFunctions = TRUE;
data_len = 0;
for (i = 0; i < vec_count; i++) {
pktpart[i+1].iov_base = payload[i].iov_base;
pktpart[i+1].iov_len = payload[i].iov_len;
data_len += payload[i].iov_len;
/* octet count only measures the payload (no extension, no SSRC lists,
etc.) */
}
buflen = _RTP_MAX_PKT_SIZE;
err = RTPBuildRTPHeader(cid, tsinc, marker, pti, FALSE /* ... XXX encrypt */,
data_len, uc->packet_buffer, &buflen);
if (err)
goto cleanup;
pktpart[0].iov_base = uc->packet_buffer;
pktpart[0].iov_len = buflen;
/* Add padding to the payload if necessary */
/* XXX encryption */
pktpart[pktlen-1].iov_base = NULL;
pktpart[pktlen-1].iov_len = 0;
/* XXX do encryption here */
/* Packet is not encrypted. Then it is ready to be sent. */
memset((char*) &the_message, 0, sizeof(the_message));
the_message.msg_name = (caddr_t) NULL;
the_message.msg_namelen = 0;
the_message.msg_iov = pktpart;
the_message.msg_iovlen = pktlen;
s = uc->send_addr_list;
err = RTP_OK;
rundelete = FALSE;
while(s != NULL) {
if(s->deleteflag == FALSE) {
errchk = _sys_sendmsg(s->rtpsocket, (struct msghdr*)
&the_message, 0);
if (errchk < 0) {
err = errordebug(RTP_SOCKET_WRITE_FAILURE, "RTPSendVector",
"context %d could not write to RTP socket",
(int)cid);
if (uc->SendErrorCallBack != NULL) {
uc->SendErrorCallBack(cid,
inet_ntoa(s->address),
ntohs(s->port),
s->ttl);
}
if (s->deleteflag == TRUE) {
rundelete = TRUE;
}
}
} else {
rundelete = TRUE;
}
s = s->next;
}
/* Now, we clean up the send list and remove all that have been deleted.
We know that this needs to be done if rundelete is TRUE */
prevs = NULL;
if(rundelete == TRUE) {
s = uc->send_addr_list;
while(s != NULL) {
if(s->deleteflag == TRUE) {
if(prevs == NULL)
uc->send_addr_list = s->next;
else
prevs->next = s->next;
_sys_close_socket(s->rtpsocket);
_sys_close_socket(s->rtcpsocket);
free(s);
}
prevs = s;
s = s->next;
}
}
cleanup:
free(pktpart);
uc->PreventEntryIntoFlaggingFunctions = FALSE;
return(err);
}