/*
 * a simple video server
 * by Hoang Nguyen (hnguyen5@illinois.edu)
 *
 * Note: 
 * No buffering/sync/rate control mechanism is used.
 * The server simply reads frames and sends to the client
 * TCP is used
 *
 * Feel free to use/modify this code
 * at YOUR OWN RISK
 *
 * Protocol: 
 * 1) Server reads the avi file, setup AVCodecContext
 * 2) Client connects, receives AVCodecContext, fixes interal pointers of AVCodecContext
 * 3) Client sends requested duration in frames, following by a READY signal 
 * 4) Server receives requested duration and starts sending frames right after receiving READY signal from the client
 * 5) Server reads frames and sends to the client for every 40ms 
 */

#include <ffmpeg/avcodec.h>
#include <ffmpeg/avformat.h>

#include <SDL.h>
#include <SDL_thread.h>

#ifdef __MINGW32__
#undef main /* Prevents SDL from overriding main() */
#endif

#include <stdio.h>
#include "msg.h"

AVFormatContext *pFormatCtx;
int             i, videoStream;
AVCodecContext  *pCodecCtx;
AVCodec         *pCodec;
AVFrame         *pFrame; 
AVPacket        packet;
int             frameFinished;
float           aspect_ratio;


void serverfunc(int sockfd) {
	int duration; // in frames

 	printf("Sending AVCodecContext structure...");
	int len = send(sockfd, (char *) pCodecCtx, sizeof(AVCodecContext), 0);	
	printf("%d finished\n", len);

	while (recv(sockfd, &duration, sizeof(duration), MSG_WAITALL) <= 0);
	printf("Client wants %d frames\n", duration);
	
	int ready;

	printf("Waiting for client to be ready...\n");
	while (recv(sockfd, &ready, sizeof(ready), MSG_WAITALL) <= 0);
	printf("\tfinished\n");

	printf("Start sending packets\n");

	long count = 1;
	while(av_read_frame(pFormatCtx, &packet)>=0) {
		// Free the packet that was allocated by av_read_frame
    		if(packet.stream_index==videoStream) {
			len = send(sockfd, (char *) packet.data, packet.size, 0);
			printf("Sent packet %ld, len = %d\n", count++, len);
			SDL_Delay(40);
		}
		av_free_packet(&packet);
 
		if (count > duration) break; 
	}
  
  	// Close the video file
  	av_close_input_file(pFormatCtx);

	exit(0);
}


int main(int argc, char *argv[]) {
  if(argc < 3) {
    fprintf(stderr, "Usage: mp3server <port> <file>\n");
    exit(1);
  }
  // Register all formats and codecs
  av_register_all();

  // Open video file
  if(av_open_input_file(&pFormatCtx, argv[2], NULL, 0, NULL)!=0)
    return -1; // Couldn't open file
  
  // Retrieve stream information
  if(av_find_stream_info(pFormatCtx)<0)
    return -1; // Couldn't find stream information
  
  // Dump information about file onto standard error
  dump_format(pFormatCtx, 0, argv[1], 0);
  
  // Find the first video stream
  videoStream=-1;
  for(i=0; i<pFormatCtx->nb_streams; i++)
    if(pFormatCtx->streams[i]->codec->codec_type==CODEC_TYPE_VIDEO) {
      videoStream=i;
      break;
    }
  if(videoStream==-1)
    return -1; // Didn't find a video stream
  
  // Get a pointer to the codec context for the video stream
  pCodecCtx=pFormatCtx->streams[videoStream]->codec;

  startServer(argv[1], (void *)(serverfunc)); 
  
  return 0;
}