我正在尝试获取 YUV 420 流,将其转换为 MPEG2 并通过 UDP 作为传输流发送。
转换似乎工作正常,通过保存输出我可以创建一个可播放的 MPEG。在wireshark 中查看传输的数据包时,我可以看到程序关联和程序映射表(它们看起来是正确的)以及b 帧和p 帧。我看不到任何 I 帧,但可以看到 MPEG 序列标头数据包。
使用 VLC 我无法查看流(UDP://239.192.1.114:6677)
下面是一段代码,展示了视频包的转换和传输。
任何关于为什么我看不到 I 帧的想法将不胜感激。
bool MPEGTransmitter::InitMPEG(int width, int height)
{
/* find the mpeg2 video encoder */
codec = avcodec_find_encoder(CODEC_ID_MPEG2VIDEO);
if (!codec)
{
//debugCb("Codec Not Found"); //fprintf(stderr, "codec not found\n");
return false;
}
codecCtxt = avcodec_alloc_context3(codec);
picture= avcodec_alloc_frame();
/* put sample parameters */
codecCtxt->bit_rate = 0;
/* resolution */
codecCtxt->width = width;
codecCtxt->height = height;
/* frames per second */
AVRational avr;
avr.den = 25;
avr.num = 1;
codecCtxt->time_base= avr;
codecCtxt->gop_size = 5; /* emit one intra frame every 5 frames */
codecCtxt->max_b_frames=2;
codecCtxt->pix_fmt = PIX_FMT_YUV420P; // 4:2:0 used for MPEG
/* open it */
if (avcodec_open2(codecCtxt, codec,NULL) < 0)
{
//debugCb("Could not open video codec"); //fprintf(stderr, "could not open codec\n");
return false;
}
/* alloc image and output buffer */
outbuf_size = 100000;
outbuf = (uint8_t*)malloc(outbuf_size);
size = codecCtxt->width * codecCtxt->height;
picture_buf = (uint8_t*)malloc((size * 3)/2); /* size for YUV 420 */
picture->data[0] = picture_buf;
picture->data[1] = picture->data[0] + size;
picture->data[2] = picture->data[1] + size/4;
picture->linesize[0] = codecCtxt->width;
picture->linesize[1] = codecCtxt->width /2 ;
picture->linesize[2] = codecCtxt->width /2;
SaveToFile(outfileName);
//MpegInitialised = true;
std::stringstream ssLog;
ssLog << "MPEG initialised with Height "<< height << " Width " << width << endl;
WriteLogMsg(ssLog.str());
return true;
}
void MPEGTransmitter::WriteFrame(unsigned char* Yarray, unsigned char* cbArray, unsigned char* crArray)
{
/* prepare the image */
/* Y */
int idx=0;
for(int y=0;y<codecCtxt->height;y++)
{
for(int x=0;x<codecCtxt->width;x++)
{
picture->data[0][y * picture->linesize[0] + x] = Yarray[idx++];
}
}
/* Cb and Cr */
for(int y=0;y < codecCtxt->height/2 ;y++)
{
for(int x=0;x< codecCtxt->width/2 ;x++)
{
picture->data[1][y * codecCtxt->width/2 + x] = (cbArray[(y*codecCtxt->width)+x] + cbArray[(y*codecCtxt->width)+ x+1])/2;
picture->data[2][y * codecCtxt->width/2 + x] = (crArray[(y*codecCtxt->width)+x] + crArray[(y*codecCtxt->width)+ x+1])/2;
}
}
/* encode the image */
out_size = avcodec_encode_video(codecCtxt, outbuf, outbuf_size, picture);
/* send the image */
WriteMpegTS(outbuf, out_size,0x1F);
/* save the image */
if( fVideoOut )
{
fwrite(outbuf, 1, out_size, fVideoOut);
}
}
void MPEGTransmitter::WriteMpegTS(uint8_t* pPayloadPkt, int iPktSize, unsigned int iPidLower)
{
int dataCounter = 0;
bool firstPacket=true;
while(dataCounter < iPktSize)
{
// TS Packets are 188 bytes long, 4 byte header followed by payload
char* pTSPkt = new char[188];
pTSPkt[0] = 0x47; // Sync byte
if(firstPacket)
{
pTSPkt[1] = 0x40; // start of payload flag set + high bytes of payload id
firstPacket=false;
}
else
{
pTSPkt[1] = 0; // start of payload flag not set + high bytes of payload id
}
pTSPkt[2] = iPidLower; // low bytes of payload id
pTSPkt[3] = 0x10 | getContinuityCounter(iPidLower); //returns the cont. counter for the specified pkt type
// Fill the rest of the packet with data, or padding if no more data to add
for(int i= 4; i< 188; i++)
{
if(dataCounter <iPktSize)
{
pTSPkt[i] = pPayloadPkt[dataCounter++];
}
else
{
pTSPkt[i] = 0xFF;
}
}
// Send the packet over multicast/rtp
unsigned int pktSize = 188;
sktMpeg->SendMsg(pTSPkt, pktSize); // calls the sendMsg function of the socket class
}