Created
November 3, 2013 13:41
-
-
Save skayred/7290391 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern "C" { | |
#include <libavcodec/avcodec.h> | |
#include <libavformat/avformat.h> | |
#include <libswscale/swscale.h> | |
} | |
#include <SDL2/SDL.h> | |
#include <stdio.h> | |
#include <iostream> | |
SDL_Texture *texture; | |
SDL_mutex* PictureMutex; | |
SDL_cond* PictureReadyCond; | |
bool PictureReady; | |
uint8_t * ToYUV420(AVFrame* frame, AVCodecContext *codecContext) { | |
static int numPixels = avpicture_get_size ( | |
PIX_FMT_YUV420P, | |
codecContext->width, | |
codecContext->height); | |
static uint8_t * buffer = (uint8_t *) malloc (numPixels); | |
//Set context for conversion | |
static struct SwsContext *swsContext = sws_getCachedContext ( | |
swsContext, | |
codecContext->width, | |
codecContext->height, | |
codecContext->pix_fmt, | |
codecContext->width, | |
codecContext->height, | |
PIX_FMT_YUV420P, | |
SWS_BILINEAR, | |
NULL, | |
NULL, | |
NULL | |
); | |
AVFrame* frameYUV420P = avcodec_alloc_frame(); | |
avpicture_fill( | |
(AVPicture *) frameYUV420P, | |
buffer, | |
PIX_FMT_YUV420P, | |
codecContext->width, | |
codecContext->height); | |
// Convert the image into YUV format that SDL uses | |
sws_scale(swsContext, | |
frame->data, frame->linesize, | |
0, codecContext->height, | |
frameYUV420P->data, frameYUV420P->linesize ); | |
return buffer; | |
} | |
void PreparePicture(AVFrame *frame, AVCodecContext *codecContext) { | |
SDL_LockMutex(PictureMutex); | |
// while (PictureReady) | |
// SDL_CondWait(PictureReadyCond, PictureMutex); | |
SDL_UnlockMutex(PictureMutex); | |
int pitch = codecContext->width * SDL_BYTESPERPIXEL(SDL_PIXELFORMAT_IYUV); | |
uint8_t * buffer = ToYUV420(frame, codecContext); | |
SDL_UpdateTexture(texture, NULL, buffer, pitch); | |
SDL_LockMutex(PictureMutex); | |
PictureReady = true; | |
SDL_CondSignal(PictureReadyCond); | |
SDL_UnlockMutex(PictureMutex); | |
} | |
void sdl_init(AVFormatContext* format_context, AVCodecContext* codecContext, int videoStream ) { | |
SDL_Init(SDL_INIT_EVERYTHING); | |
AVFrame* frame; | |
AVFrame *pFrameRGB; | |
AVPacket avpacket; | |
AVPicture picture; | |
int w = 640; | |
int h = 480; | |
SDL_Window *screen = SDL_CreateWindow("SDL", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, w, h, 0); | |
SDL_Renderer *renderer = SDL_CreateRenderer(screen, -1, 0); | |
texture = SDL_CreateTexture(renderer, | |
SDL_PIXELFORMAT_IYUV, // YUV420P | |
SDL_TEXTUREACCESS_STREAMING, | |
codecContext->width, | |
codecContext->height); | |
PictureMutex = SDL_CreateMutex(); | |
PictureReadyCond = SDL_CreateCond(); | |
PictureReady = false; | |
frame = avcodec_alloc_frame(); | |
pFrameRGB = avcodec_alloc_frame(); | |
if (pFrameRGB == NULL) { | |
printf("Cannot allocate pFrame\n"); | |
exit(-1); | |
} | |
unsigned char* pixels; | |
int pitch; | |
uint8_t *buffer; | |
int numBytes; | |
// Determine required buffer size and allocate buffer | |
numBytes=avpicture_get_size(PIX_FMT_RGB24, codecContext->width, codecContext->height); | |
buffer=(uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); | |
// Assign appropriate parts of buffer to image planes in pFrameRGB | |
// Note that pFrameRGB is an AVFrame, but AVFrame is a superset | |
// of AVPicture | |
avpicture_fill((AVPicture *)pFrameRGB, buffer, PIX_FMT_RGB24, codecContext->width, codecContext->height); | |
while (av_read_frame(format_context, &avpacket) >= 0) { | |
if (avpacket.stream_index == videoStream) { | |
// Video stream packet | |
int frame_finished; | |
avcodec_decode_video2(codecContext, frame, &frame_finished, &avpacket); | |
if(frame_finished) { | |
std::cout << "--" << std::endl; | |
PreparePicture(frame, codecContext); | |
}//frame | |
av_free_packet(&avpacket); | |
}//avpacket | |
SDL_Delay(20); | |
} | |
SDL_Quit(); | |
} | |
int main(int argc, char * argv[]) { | |
AVCodecContext* codec_context; | |
int videoStream; | |
if (argc < 2) { | |
printf("Usage: %s filename\n", argv[0]); | |
return 0; | |
} | |
// Register all available file formats and codecs | |
av_register_all(); | |
int err; | |
// Init SDL with video support | |
err = SDL_Init(SDL_INIT_VIDEO); | |
if (err < 0) { | |
fprintf(stderr, "Unable to init SDL: %s\n", SDL_GetError()); | |
return -1; | |
} | |
// Open video file | |
const char* filename = argv[1]; | |
AVFormatContext* format_context = NULL; | |
err = avformat_open_input(&format_context, filename, NULL, NULL); | |
if (err < 0) { | |
fprintf(stderr, "ffmpeg: Unable to open input\n"); | |
return -1; | |
} | |
// Retrieve stream information | |
err = avformat_find_stream_info(format_context, NULL); | |
if (err < 0) { | |
fprintf(stderr, "ffmpeg: Unable to find stream info\n"); | |
return -1; | |
} | |
// Dump information about file onto standard error | |
av_dump_format(format_context, 0, argv[1], 0); | |
// Find the first video stream | |
for (videoStream = 0; videoStream < format_context->nb_streams; ++videoStream) { | |
if (format_context->streams[videoStream]->codec->codec_type == AVMEDIA_TYPE_VIDEO) { | |
break; | |
} | |
} | |
if (videoStream == format_context->nb_streams) { | |
fprintf(stderr, "ffmpeg: Unable to find video stream\n"); | |
return -1; | |
} | |
codec_context = format_context->streams[videoStream]->codec; | |
AVCodec* codec = avcodec_find_decoder(codec_context->codec_id); | |
avcodec_alloc_context3(codec); | |
if (avcodec_open2(codec_context, codec, NULL) < 0) { | |
fprintf(stderr, "ffmpeg: Unable to allocate codec context\n"); | |
} else { | |
printf("Codec initialized\n"); | |
} | |
printf("Width:%d\n",codec_context->width); | |
printf("height:%d\n",codec_context->height); | |
sdl_init(format_context, codec_context,videoStream); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment