├── Audio.cpp ├── Audio.h ├── AudioCallback.cpp ├── AudioCallback.h ├── AudioPacket.h ├── LICENSE ├── Player.cpp ├── Player.h ├── README.md ├── SDLWrapper.cpp ├── SDLWrapper.h ├── Utils.cpp ├── Utils.h ├── defs.h ├── main.cpp ├── makefile ├── makefile_windows └── stdafx.h /Audio.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | Audio* Audio::instance = 0; 4 | 5 | Audio* Audio::get_instance() 6 | { 7 | if (instance == 0) 8 | instance = new Audio(); 9 | return instance; 10 | } 11 | 12 | void Audio::open() 13 | { 14 | SDLWrapper::open_audio(&wantedSpec, &audioSpec); 15 | 16 | wanted_frame.format = AV_SAMPLE_FMT_S16; 17 | wanted_frame.sample_rate = audioSpec.freq; 18 | wanted_frame.channel_layout = av_get_default_channel_layout(audioSpec.channels); 19 | wanted_frame.channels = audioSpec.channels; 20 | 21 | init_audio_packet(&audioq); 22 | SDL_PauseAudio(0); 23 | } 24 | 25 | void Audio::init_audio_packet(AudioPacket* q) 26 | { 27 | q->last = NULL; 28 | q->first = NULL; 29 | q->mutex = SDL_CreateMutex(); 30 | q->cond = SDL_CreateCond(); 31 | } 32 | 33 | void Audio::malloc(AVCodecContext* pCodecAudioCtx) 34 | { 35 | AudioCallback::set_audio_instance(this); 36 | 37 | swrCtx = swr_alloc(); 38 | if (swrCtx == NULL) 39 | Utils::display_exception("Failed to load audio"); 40 | 41 | av_opt_set_channel_layout(swrCtx, "in_channel_layout", pCodecAudioCtx->channel_layout, 0); 42 | av_opt_set_channel_layout(swrCtx, "out_channel_layout", pCodecAudioCtx->channel_layout, 0); 43 | av_opt_set_int(swrCtx, "in_sample_rate", pCodecAudioCtx->sample_rate, 0); 44 | av_opt_set_int(swrCtx, "out_sample_rate", pCodecAudioCtx->sample_rate, 0); 45 | av_opt_set_sample_fmt(swrCtx, "in_sample_fmt", pCodecAudioCtx->sample_fmt, 0); 46 | av_opt_set_sample_fmt(swrCtx, "out_sample_fmt", AV_SAMPLE_FMT_FLT, 0); 47 | 48 | int res = swr_init(swrCtx); 49 | 50 | if (res != 0) 51 | Utils::display_exception("Failed to initialize audio"); 52 | 53 | memset(&wantedSpec, 0, sizeof(wantedSpec)); 54 | 55 | wantedSpec.channels = pCodecAudioCtx->channels; 56 | wantedSpec.freq = pCodecAudioCtx->sample_rate; 57 | wantedSpec.format = AUDIO_S16SYS; 58 | wantedSpec.silence = 0; 59 | wantedSpec.samples = SDL_AUDIO_BUFFER_SIZE; 60 | wantedSpec.userdata = pCodecAudioCtx; 61 | wantedSpec.callback = AudioCallback::audio_callback; 62 | } 63 | 64 | int Audio::audio_decode_frame(AVCodecContext* aCodecCtx, uint8_t* audio_buf, int buf_size) { 65 | 66 | static AVPacket pkt; 67 | static uint8_t* audio_pkt_data = NULL; 68 | static int audio_pkt_size = 0; 69 | static AVFrame frame; 70 | 71 | int len1; 72 | int data_size = 0; 73 | 74 | SwrContext* swr_ctx = NULL; 75 | 76 | while (1) 77 | { 78 | while (audio_pkt_size > 0) 79 | { 80 | int got_frame = 0; 81 | 82 | avcodec_send_packet(aCodecCtx, &pkt); 83 | avcodec_receive_frame(aCodecCtx, &frame); 84 | 85 | len1 = frame.pkt_size; 86 | if (len1 < 0) 87 | { 88 | audio_pkt_size = 0; 89 | break; 90 | } 91 | 92 | audio_pkt_data += len1; 93 | audio_pkt_size -= len1; 94 | 95 | data_size = 0; 96 | 97 | if (got_frame) 98 | { 99 | int linesize = 1; 100 | data_size = av_samples_get_buffer_size(&linesize, aCodecCtx->channels, frame.nb_samples, aCodecCtx->sample_fmt, 1); 101 | assert(data_size <= buf_size); 102 | memcpy(audio_buf, frame.data[0], data_size); 103 | } 104 | 105 | if (frame.channels > 0 && frame.channel_layout == 0) 106 | frame.channel_layout = av_get_default_channel_layout(frame.channels); 107 | else if (frame.channels == 0 && frame.channel_layout > 0) 108 | frame.channels = av_get_channel_layout_nb_channels(frame.channel_layout); 109 | 110 | if (swr_ctx) 111 | { 112 | swr_free(&swr_ctx); 113 | swr_ctx = NULL; 114 | } 115 | 116 | swr_ctx = swr_alloc_set_opts(NULL, wanted_frame.channel_layout, (AVSampleFormat)wanted_frame.format, wanted_frame.sample_rate, 117 | frame.channel_layout, (AVSampleFormat)frame.format, frame.sample_rate, 0, NULL); 118 | 119 | if (!swr_ctx || swr_init(swr_ctx) < 0) 120 | Utils::display_exception("swr_init failed"); 121 | 122 | int dst_nb_samples = (int)av_rescale_rnd(swr_get_delay(swr_ctx, frame.sample_rate) + frame.nb_samples, 123 | wanted_frame.sample_rate, wanted_frame.format, AV_ROUND_INF); 124 | 125 | int len2 = swr_convert(swr_ctx, &audio_buf, dst_nb_samples, 126 | (const uint8_t**)frame.data, frame.nb_samples); 127 | if (len2 < 0) 128 | Utils::display_exception("swr_convert failed"); 129 | 130 | av_packet_unref(&pkt); 131 | 132 | if (swr_ctx) 133 | { 134 | swr_free(&swr_ctx); 135 | swr_ctx = NULL; 136 | } 137 | 138 | return wanted_frame.channels * len2 * av_get_bytes_per_sample(AV_SAMPLE_FMT_S16); 139 | } 140 | 141 | if (Player::get_instance()->getAudioPacket(&audioq, &pkt, 1) < 0) 142 | return -1; 143 | 144 | audio_pkt_data = pkt.data; 145 | audio_pkt_size = pkt.size; 146 | } 147 | } 148 | 149 | int Audio::put_audio_packet(AVPacket* packet) 150 | { 151 | AVPacketList* pktl; 152 | AVPacket* newPkt; 153 | newPkt = (AVPacket*)av_mallocz_array(1, sizeof(AVPacket)); 154 | if (av_packet_ref(newPkt, packet) < 0) 155 | return -1; 156 | 157 | pktl = (AVPacketList*)av_malloc(sizeof(AVPacketList)); 158 | if (!pktl) 159 | return -1; 160 | 161 | pktl->pkt = *newPkt; 162 | pktl->next = NULL; 163 | 164 | SDL_LockMutex(audioq.mutex); 165 | 166 | if (!audioq.last) 167 | audioq.first = pktl; 168 | else 169 | audioq.last->next = pktl; 170 | 171 | audioq.last = pktl; 172 | 173 | audioq.nb_packets++; 174 | audioq.size += newPkt->size; 175 | 176 | SDL_CondSignal(audioq.cond); 177 | SDL_UnlockMutex(audioq.mutex); 178 | 179 | return 0; 180 | } -------------------------------------------------------------------------------- /Audio.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class Audio 3 | { 4 | public: 5 | static Audio* get_instance(); 6 | 7 | struct SwrContext* swrCtx = NULL; 8 | AVFrame wanted_frame; 9 | 10 | AudioPacket audioq; 11 | 12 | void open(); 13 | void malloc(AVCodecContext*); 14 | void init_audio_packet(AudioPacket*); 15 | int audio_decode_frame(AVCodecContext*, uint8_t*, int); 16 | int put_audio_packet(AVPacket*); 17 | 18 | private: 19 | Audio() {} 20 | static Audio* instance; 21 | 22 | SDL_AudioSpec wantedSpec = { 0 }, audioSpec = { 0 }; 23 | }; -------------------------------------------------------------------------------- /AudioCallback.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | Audio* AudioCallback::audio_instance = 0; 3 | void AudioCallback::set_audio_instance(Audio* audio_instance) 4 | { 5 | AudioCallback::audio_instance = audio_instance; 6 | } 7 | 8 | void AudioCallback::audio_callback(void* userdata, Uint8* stream, int len) 9 | { 10 | AVCodecContext* aCodecCtx = (AVCodecContext*)userdata; 11 | int len1, audio_size; 12 | 13 | static uint8_t audio_buff[192000 * 3 / 2]; 14 | static unsigned int audio_buf_size = 0; 15 | static unsigned int audio_buf_index = 0; 16 | 17 | SDL_memset(stream, 0, len); 18 | 19 | while (len > 0) 20 | { 21 | if (audio_buf_index >= audio_buf_size) 22 | { 23 | audio_size = AudioCallback::audio_instance->audio_decode_frame(aCodecCtx, audio_buff, sizeof(audio_buff)); 24 | if (audio_size < 0) 25 | { 26 | audio_buf_size = 1024; 27 | memset(audio_buff, 0, audio_buf_size); 28 | } 29 | else 30 | audio_buf_size = audio_size; 31 | 32 | audio_buf_index = 0; 33 | } 34 | len1 = audio_buf_size - audio_buf_index; 35 | if (len1 > len) 36 | len1 = len; 37 | 38 | SDL_MixAudio(stream, audio_buff + audio_buf_index, len, SDL_MIX_MAXVOLUME); 39 | 40 | len -= len1; 41 | stream += len1; 42 | audio_buf_index += len1; 43 | } 44 | } -------------------------------------------------------------------------------- /AudioCallback.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class AudioCallback 3 | { 4 | public: 5 | static void set_audio_instance(Audio*); 6 | static void audio_callback(void*, Uint8*, int); 7 | 8 | private: 9 | AudioCallback() {} 10 | 11 | static Audio* audio_instance; 12 | }; -------------------------------------------------------------------------------- /AudioPacket.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | typedef struct _AudioPacket 3 | { 4 | AVPacketList* first, * last; 5 | int nb_packets, size; 6 | SDL_mutex* mutex; 7 | SDL_cond* cond; 8 | } AudioPacket; -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Raul Alves 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Player.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | using namespace std; 4 | 5 | Player* Player::instance = 0; 6 | Player* Player::get_instance() 7 | { 8 | if (instance == 0) 9 | instance = new Player(); 10 | return instance; 11 | } 12 | 13 | void Player::run(std::string video_addr, std::string window_name) 14 | { 15 | this->video_addr = video_addr; 16 | this->window_name = window_name; 17 | 18 | this->open(); 19 | this->malloc(); 20 | this->create_display(); 21 | this->display_video(); 22 | } 23 | 24 | void Player::open() 25 | { 26 | audioStream = -1; 27 | 28 | // open video 29 | int res = avformat_open_input(&pFormatCtx, this->video_addr.c_str(), NULL, NULL); 30 | 31 | // check video 32 | if (res != 0) 33 | Utils::display_ffmpeg_exception(res); 34 | 35 | // get video info 36 | res = avformat_find_stream_info(pFormatCtx, NULL); 37 | if (res < 0) 38 | Utils::display_ffmpeg_exception(res); 39 | 40 | // get video stream 41 | videoStream = get_video_stream(); 42 | if (videoStream == -1) 43 | Utils::display_exception("Error opening your video using AVCodecParameters, probably doesnt have codecpar_type type AVMEDIA_TYPE_VIDEO"); 44 | 45 | // open 46 | read_audio_video_codec(); 47 | } 48 | 49 | void Player::clear() 50 | { 51 | // close context info 52 | avformat_close_input(&pFormatCtx); 53 | avcodec_free_context(&pCodecCtx); 54 | 55 | // free buffers 56 | av_free(buffer); 57 | av_free(pFrameRGB); 58 | 59 | // Free the YUV frame 60 | av_free(pFrame); 61 | 62 | // Close the codecs 63 | avcodec_close(pCodecCtx); 64 | 65 | // Close the video file 66 | avformat_close_input(&pFormatCtx); 67 | 68 | delete Player::get_instance(); 69 | } 70 | 71 | /* 72 | Acquires video stream 73 | */ 74 | int Player::get_video_stream(void) 75 | { 76 | int videoStream = -1; 77 | 78 | for (unsigned int i = 0; inb_streams; i++){ 79 | if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) videoStream = i; 80 | if (pFormatCtx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) audioStream = i; 81 | } 82 | 83 | if (videoStream == -1) 84 | Utils::display_exception("Couldnt find stream"); 85 | 86 | pCodecParameters = pFormatCtx->streams[videoStream]->codecpar; 87 | if(audioStream != -1) pCodecAudioParameters = pFormatCtx->streams[audioStream]->codecpar; 88 | 89 | return videoStream; 90 | } 91 | 92 | /* 93 | Reads audio and video codec 94 | */ 95 | int Player::read_audio_video_codec(void) 96 | { 97 | pCodec = avcodec_find_decoder(pCodecParameters->codec_id); 98 | pAudioCodec = avcodec_find_decoder(pCodecAudioParameters->codec_id); 99 | 100 | if (pCodec == NULL) 101 | Utils::display_exception("Video decoder not found"); 102 | 103 | if (pAudioCodec == NULL) 104 | Utils::display_exception("Audio decoder not found"); 105 | 106 | pCodecCtx = avcodec_alloc_context3(pCodec); 107 | 108 | if(pCodecCtx == NULL) 109 | Utils::display_exception("Failed to allocate video context decoder"); 110 | 111 | pCodecAudioCtx = avcodec_alloc_context3(pAudioCodec); 112 | 113 | if(pCodecAudioCtx == NULL) 114 | Utils::display_exception("Failed to allocate audio context decoder"); 115 | 116 | int res = avcodec_parameters_to_context(pCodecCtx, pCodecParameters); 117 | 118 | if(res < 0) 119 | Utils::display_exception("Failed to transfer video parameters to context"); 120 | 121 | res = avcodec_parameters_to_context(pCodecAudioCtx, pCodecAudioParameters); 122 | 123 | if (res < 0) 124 | Utils::display_exception("Failed to transfer audio parameters to context"); 125 | 126 | res = avcodec_open2(pCodecCtx, pCodec, NULL); 127 | 128 | if(res < 0) 129 | Utils::display_exception("Failed to open video codec"); 130 | 131 | res = avcodec_open2(pCodecAudioCtx, pAudioCodec, NULL); 132 | 133 | if (res < 0) 134 | Utils::display_exception("Failed to open auvio codec"); 135 | 136 | return 1; 137 | } 138 | 139 | /* 140 | Alloc memory for the display 141 | */ 142 | int Player::malloc(void) 143 | { 144 | Audio::get_instance()->malloc(pCodecAudioCtx); 145 | 146 | Audio::get_instance()->open(); 147 | 148 | pFrame = av_frame_alloc(); 149 | if (pFrame == NULL) 150 | Utils::display_exception("Couldnt allocate frame memory"); 151 | 152 | pFrameRGB = av_frame_alloc(); 153 | if (pFrameRGB == NULL) 154 | Utils::display_exception("Couldnt allocate rgb frame memory"); 155 | 156 | int numBytes = av_image_get_buffer_size(VIDEO_FORMAT, pCodecCtx->width, pCodecCtx->height,1); 157 | 158 | buffer = (uint8_t *)av_malloc(numBytes*sizeof(uint8_t)); 159 | 160 | int res = av_image_fill_arrays(pFrameRGB->data, pFrameRGB->linesize, buffer, VIDEO_FORMAT, pCodecCtx->width, pCodecCtx->height, 1); 161 | if (res < 0) 162 | Utils::display_ffmpeg_exception(res); 163 | 164 | return 1; 165 | } 166 | 167 | 168 | int Player::getAudioPacket(AudioPacket* q, AVPacket* pkt, int block){ 169 | 170 | AVPacketList* pktl; 171 | int ret; 172 | 173 | SDL_LockMutex(q->mutex); 174 | 175 | while (1) 176 | { 177 | pktl = q->first; 178 | if (pktl) 179 | { 180 | q->first = pktl->next; 181 | if (!q->first) 182 | q->last = NULL; 183 | 184 | q->nb_packets--; 185 | q->size -= pktl->pkt.size; 186 | 187 | *pkt = pktl->pkt; 188 | av_free(pktl); 189 | ret = 1; 190 | break; 191 | } 192 | else if (!block) 193 | { 194 | ret = 0; 195 | break; 196 | } 197 | else 198 | { 199 | SDL_CondWait(q->cond, q->mutex); 200 | } 201 | } 202 | 203 | SDL_UnlockMutex(q->mutex); 204 | 205 | return ret; 206 | } 207 | 208 | /* 209 | Read frames and display 210 | */ 211 | int Player::display_video(void) { 212 | 213 | AVPacket packet; 214 | 215 | //video context 216 | sws_ctx = sws_getContext(pCodecCtx->width, 217 | pCodecCtx->height, 218 | pCodecCtx->pix_fmt, 219 | pCodecCtx->width, 220 | pCodecCtx->height, 221 | VIDEO_FORMAT, 222 | SWS_BILINEAR, 223 | NULL, 224 | NULL, 225 | NULL 226 | ); 227 | SDL_Event evt; 228 | 229 | while (av_read_frame(pFormatCtx, &packet) >= 0) { 230 | 231 | if (packet.stream_index == audioStream) { 232 | Audio::get_instance()->put_audio_packet(&packet); 233 | } 234 | 235 | if (packet.stream_index == videoStream) 236 | { 237 | 238 | int res = avcodec_send_packet(pCodecCtx, &packet); 239 | if (res < 0) 240 | Utils::display_ffmpeg_exception(res); 241 | 242 | res = avcodec_receive_frame(pCodecCtx, pFrame); 243 | 244 | SDL_UpdateYUVTexture(bmp, NULL, pFrame->data[0], pFrame->linesize[0], 245 | pFrame->data[1], pFrame->linesize[1], 246 | pFrame->data[2], pFrame->linesize[2]); 247 | SDL_RenderCopy(renderer, bmp, NULL, NULL); 248 | SDL_RenderPresent(renderer); 249 | SDL_UpdateWindowSurface(screen); 250 | SDL_Delay(1000/30); 251 | } 252 | 253 | SDL_PollEvent(&evt); 254 | 255 | av_packet_unref(&packet); 256 | } 257 | 258 | return 1; 259 | 260 | } 261 | 262 | /* 263 | Create the display for the received video 264 | */ 265 | int Player::create_display(void) 266 | { 267 | screen = SDL_CreateWindow(window_name.c_str(), 268 | SDL_WINDOWPOS_CENTERED, 269 | SDL_WINDOWPOS_CENTERED, 270 | pCodecCtx->width, pCodecCtx->height, 271 | SDL_WINDOW_OPENGL); 272 | 273 | if (!screen) 274 | Utils::display_exception("Couldn't show display window"); 275 | 276 | renderer = SDL_CreateRenderer(screen, -1, 0); 277 | 278 | bmp = SDL_CreateTexture(renderer, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STATIC, pCodecCtx->width, pCodecCtx->height); 279 | 280 | return 1; 281 | } -------------------------------------------------------------------------------- /Player.h: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | class Player 4 | { 5 | 6 | public: 7 | static Player* get_instance(); 8 | 9 | void run(std::string, std::string window_name=""); 10 | void clear(); 11 | 12 | static int getAudioPacket(AudioPacket*, AVPacket*, int); 13 | 14 | private: 15 | static Player* instance; 16 | Player() {} 17 | 18 | void open(); 19 | 20 | int malloc(void); 21 | int display_video(void); 22 | int create_display(void); 23 | 24 | int get_video_stream(void); 25 | 26 | int read_audio_video_codec(void); 27 | 28 | std::string video_addr; 29 | std::string window_name; 30 | 31 | int videoStream = 0; 32 | int audioStream = 0; 33 | 34 | AVFormatContext* pFormatCtx = NULL; 35 | 36 | AVCodecParameters* pCodecParameters = NULL; 37 | AVCodecParameters* pCodecAudioParameters = NULL; 38 | 39 | AVCodecContext* pCodecCtx = NULL; 40 | AVCodecContext* pCodecAudioCtx = NULL; 41 | 42 | AVCodec* pCodec = NULL; 43 | AVCodec* pAudioCodec = NULL; 44 | AVFrame* pFrame = NULL; 45 | AVFrame* pFrameRGB = NULL; 46 | 47 | uint8_t* buffer = NULL; 48 | 49 | SDL_Window* screen = NULL; 50 | SDL_Renderer* renderer = NULL; 51 | SDL_Texture* bmp = NULL; 52 | 53 | struct SwsContext* sws_ctx = NULL; 54 | }; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Simple C++ video player using FFmpeg 4 and SDL 2.0 2 | 3 | Supports video with audio. 4 | ## Windows setup (Tested on x64 environment) 5 | 1 - Install FFMpeg here https://ffmpeg.zeranoe.com/builds/win64/dev/ and add it to your path 6 | 7 | 2 - Install SDL here https://www.libsdl.org/download-2.0.php and add it to your path 8 | 9 | 3 - (Optional) Install g++ and make from MinGW https://sourceforge.net/projects/mingw/ 10 | 11 | 4 - Create a env variable to the /include folder of the FFmpeg folder: , and for the lib folder 12 | 13 | 5 - Create a env variable to the /include folder of the SDL2 folder: 14 | 15 | 6 - Run make 16 |
17 | ``` 18 | make -f makefile_windows 19 | ``` 20 | 21 | 7 - Run
22 | ``` 23 | ./player 24 | ``` 25 | 26 | ## Linux setup (Tested on Ubuntu) 27 | 28 | 1 - Install FFmpeg version >= 4 29 |
30 | ``` 31 | sudo apt update && sudo apt install ffmpeg x264 x265 libavdevice-dev 32 | ``` 33 | 34 | 2 - Install SDL >= 2.0
35 | ``` 36 | sudo apt-get install libsdl2-dev 37 | ``` 38 | 39 | 3 - Install:
40 | ``` 41 | make 42 | ``` 43 | 44 | 4 - Run
45 | ``` 46 | ./player 47 | ``` -------------------------------------------------------------------------------- /SDLWrapper.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | void SDLWrapper::init_sdl() 3 | { 4 | if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER)) 5 | Utils::display_exception("There is something wrong with your SDL Libs. Couldn't run"); 6 | 7 | #ifdef _WIN32 8 | SDL_AudioInit("directsound"); 9 | #endif 10 | } 11 | 12 | void SDLWrapper::open_audio(SDL_AudioSpec* desired, SDL_AudioSpec* obtained) 13 | { 14 | if (SDL_OpenAudio(desired, obtained) < 0) 15 | Utils::display_exception("Failed to open audio"); 16 | } -------------------------------------------------------------------------------- /SDLWrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class SDLWrapper 3 | { 4 | public: 5 | static void init_sdl(); 6 | static void open_audio(SDL_AudioSpec*, SDL_AudioSpec*); 7 | 8 | private: 9 | SDLWrapper() {}; 10 | }; -------------------------------------------------------------------------------- /Utils.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | void Utils::display_exception(const char * message) 4 | { 5 | Player::get_instance()->clear(); 6 | throw std::runtime_error(message); 7 | } 8 | 9 | void Utils::display_ffmpeg_exception(int error_code) 10 | { 11 | char error_buf[ERROR_SIZE]; 12 | av_strerror(error_code, error_buf, ERROR_SIZE); 13 | display_exception(error_buf); 14 | } -------------------------------------------------------------------------------- /Utils.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | class Utils 3 | { 4 | public: 5 | static void display_exception(const char *); 6 | static void display_ffmpeg_exception(int); 7 | 8 | private: 9 | Utils() {} 10 | }; -------------------------------------------------------------------------------- /defs.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define SDL_MAIN_HANDLED 4 | #define ERROR_SIZE 128 5 | #define VIDEO_FORMAT AV_PIX_FMT_RGB24 6 | #define SDL_AUDIO_BUFFER_SIZE 1024; 7 | #define AVCODEC_MAX_AUDIO_FRAME_SIZE 192000 -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | #include "stdafx.h" 2 | 3 | #ifdef main 4 | #undef main 5 | #endif 6 | 7 | int main(int argc, const char *argv[]) 8 | { 9 | if(argc != 2){ 10 | std::cout << "Usage: ./player "<run(argv[1]); 17 | 18 | Player::get_instance()->clear(); 19 | } -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | CC = g++ -std=c++11 2 | CFLAGS = -g -Wall 3 | SRCS = *.cpp 4 | PROG = player 5 | 6 | LIBS_CONFIG = `pkg-config --libs libavformat libavcodec libswresample libswscale libavutil sdl2` 7 | 8 | LIBS := $(LIBS_CONFIG) 9 | 10 | $(PROG):$(SRCS) 11 | $(CC) $(CFLAGS) -o $(PROG) $(SRCS) $(LIBS) -------------------------------------------------------------------------------- /makefile_windows: -------------------------------------------------------------------------------- 1 | CC = g++ -std=c++11 -g -Wall 2 | IFLAGS = -I${FFmpeg_include} -I${SDL2_include} 3 | LDFLAGS = -L${FFmpeg_lib} -L${SDL2_lib} 4 | LDFLAGS += -lSDL2 -lavcodec -lavdevice -lavfilter -lavformat -lavutil -lpostproc -lswresample -lswscale 5 | SRCS = *.cpp 6 | PROG = player 7 | 8 | $(PROG):$(SRCS) 9 | $(CC) $(IFLAGS) -o $(PROG) $(SRCS) $(LDFLAGS) -------------------------------------------------------------------------------- /stdafx.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | extern "C" 7 | { 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | } 20 | #include "SDL2/SDL.h" 21 | #include "SDL2/SDL_thread.h" 22 | #include "SDL2/SDL_syswm.h" 23 | #include "SDL2/SDL_render.h" 24 | #include "SDL2/SDL_audio.h" 25 | 26 | #include 27 | #include 28 | 29 | #include "defs.h" 30 | #include "Utils.h" 31 | #include "SDLWrapper.h" 32 | #include "AudioPacket.h" 33 | #include "Audio.h" 34 | #include "AudioCallback.h" 35 | #include "Player.h" --------------------------------------------------------------------------------