[Libav-user] Problems when trying to read an MPEG-TS file
Johannes Schmid
j.schmid at mit-xperts.com
Mon May 28 10:44:21 EEST 2018
Hi all,
I have an MPEG-TS file containing AVC video recorded from TV (DVB-S) and
I simply cannot get a single frame from that file. However, when I try
to read/convert it with ffmpeg, it seems to have no problem at all.
Basically, the code works fine with MPEG2 video codec and even HEAVC
video codecs, but not with AVC. Maybe someone can point me to the error
in this code (it is demo code, so yes, I know it does not clean up
properly).
In case someone wants to look at the MPEG-TS file (demo code expectes it
to be test.ts in local file system), you can download it here:
http://download.mit-xperts.com/test.ts
I tested it with the latest nightly snapshot build, but also with the
4.0 release (even with the 3.4.2 release). What happens is that I
receive the full metadata information (codec, video height and width,
etc.), I can send hundreds of frames/packets (read from the sample file)
via avcodec_send_packet, but avcodec_receive_frame never gives me a
single decoded frame.
Many thanks in advance for your help,
-Johannes
----------------- C++ Code follows: -----------------
#include <stdio.h>
#include <stdlib.h>
extern "C"
{
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavformat/avio.h>
#include <libavutil/error.h>
#include <libavutil/imgutils.h>
#include <libswscale/swscale.h>
}
FILE* file = NULL;
/** the size of one transport stream packet in bytes. */
#define PACKET_SIZE 188
/** the size of the transport stream buffer in bytes. */
#define TS_BUF_SIZE (100*PACKET_SIZE)
static int staticReadPacket(void *opaque, uint8_t *buf,
int buf_size) {
int size = fread(buf, 1, buf_size, file);
printf("staticReadPacket %d: %d\n", buf_size, size);
if (size>0) {
return size;
}
return AVERROR(EINTR);
}
int main(int argc, char **argv) {
file = fopen("test.ts", "rb");
if (!file) {
printf("opening file test.ts failed\n");
return 1;
}
AVFormatContext* fmtCtx = NULL;
AVIOContext* avioCtx = NULL;
AVCodec* dec = NULL;
AVCodecContext* decCtx = NULL;
int srcWidth = 0, srcHeight = 0;
enum AVPixelFormat srcFmt = AV_PIX_FMT_NONE;
uint8_t* srcData[4];
int srcLineSize[4];
AVFrame* srcFrame = NULL;
AVPacket pkt;
memset(srcData, 0, sizeof(srcData));
memset(srcLineSize, 0, sizeof(srcLineSize));
srcFrame = NULL;
av_init_packet(&pkt);
pkt.data = NULL;
pkt.size = 0;
fmtCtx = avformat_alloc_context();
if (!fmtCtx) {
printf("avformat_alloc_context failed\n");
return 1;
}
int ret = 0;
unsigned char* buffer = (unsigned char*)av_malloc(TS_BUF_SIZE);
if (!buffer) {
printf("av_malloc failed\n");
return 1;
}
avioCtx = avio_alloc_context(buffer, TS_BUF_SIZE, 0, NULL,
staticReadPacket, NULL, NULL);
if (!avioCtx) {
printf("avio_alloc_context failed\n");
return 1;
}
fmtCtx->flags |= AVFMT_FLAG_CUSTOM_IO;
fmtCtx->pb = avioCtx;
AVInputFormat* infmt = av_find_input_format("mpegts");
if (!infmt) {
printf("av_find_input_format failed\n");
return 1;
}
AVDictionary* opts = NULL;
av_dict_set(&opts, "scan_all_pmts", "0", 0);
ret = avformat_open_input(&fmtCtx, NULL, infmt, &opts);
if (opts) {
av_dict_free(&opts);
}
if (ret<0) {
printf("avformat_open_input failed\n");
return 1;
}
opts = NULL;
ret = avformat_find_stream_info(fmtCtx, &opts);
if (opts) {
av_dict_free(&opts);
}
if (ret<0) {
printf("avformat_find_streainfo failed\n");
return 1;
}
decCtx = avcodec_alloc_context3(dec);
if (decCtx==NULL) {
printf("avcodec_alloc_context3 failed\n");
return 1;
}
ret = av_find_best_stream(fmtCtx, AVMEDIA_TYPE_VIDEO,
-1, -1, &dec, 0);
if (ret<0) {
printf("av_find_best_stream failed\n");
return 1;
}
ret = avcodec_parameters_to_context(decCtx,
fmtCtx->streams[ret]->codecpar);
if (ret<0) {
printf("avcodec_copy_context failed\n");
return 1;
}
decCtx->skip_frame = AVDISCARD_NONKEY;
opts = NULL;
ret = avcodec_open2(decCtx, dec, &opts);
if (opts) {
av_dict_free(&opts);
}
if (ret<0) {
printf("avcodec_open2 failed\n");
return 1;
}
srcWidth = decCtx->width;
srcHeight = decCtx->height;
srcFmt = decCtx->pix_fmt;
ret = av_image_alloc(srcData, srcLineSize,
srcWidth, srcHeight, srcFmt, 1);
if (ret<0) {
printf("av_image_alloc failed\n");
return 1;
}
srcFrame = av_frame_alloc();
if (!srcFrame) {
printf("av_frame_alloc failed\n");
return 1;
}
printf("Start reading frame: %d x %d\n", srcWidth, srcHeight);
// fseek(file, 0, SEEK_SET);
while (true) {
ret = av_read_frame(fmtCtx, &pkt);
if (ret>=0) {
printf("av_read_frame\n");
ret = avcodec_send_packet(decCtx, &pkt);
av_packet_unref(&pkt);
if (ret==0) {
printf("Packet sent.\n");
} else {
printf("Sending packet failed: %d\n", ret);
break;
}
} else {
printf("no more data\n");
avcodec_send_packet(decCtx, NULL);
}
ret = avcodec_receive_frame(decCtx, srcFrame);
if (ret==0) {
printf("Got frame!\n");
break;
} else if (ret==AVERROR(EAGAIN)) {
printf("Need more input, sending packet...\n");
} else if (ret==AVERROR(EINVAL)) {
printf("Receive frame error EINVAL!\n");
break;
} else if (ret==AVERROR_EOF) {
printf("Receive frame error EOF!\n");
break;
} else {
printf("Receive frame error %d!\n", ret);
}
}
return 0;
}
More information about the Libav-user
mailing list