2016-08-18 11 views
1

Что я делаю, это приложение IOS с Xcode 7.3.mux raw h 264 в файл mp4, некоторые нечетные ошибки

Я получил данные h264 с ip-камеры с использованием UDP, данные могут быть декодированы и отображены правильно (декодировано ffmpeg). Теперь я хочу отобразить необработанные данные H264 в файле mp4 (некоторые пользователи могут записывать то, что они смотрят на своем мобильном телефоне), используя ffmpeg. При запуске кода ничего плохого не произошло, и файл результатов можно воспроизводить в обычном режиме с помощью QuickTime на моем компьютере. Но когда играется на iphone с помощью видеопроигрывателя по умолчанию iphone, его нельзя воспроизводить нормально. Вот мой код.

Пожелайте, чтобы кто-нибудь мог сказать мне, что мне делать, спасибо!

INIT

AVFormatContext *formatContext; 
AVOutputFormat *outputFormat; 
AVStream *video_st; 
int STREAM_FRAME_RATE = 15; 
unsigned long video_PTS; 
int initRecorder(char *fileName, int width, int height) { 
    video_st = NULL; 
    video_PTS = 0; 

    av_register_all(); 

    outputFormat = av_guess_format(NULL, fileName, NULL); 
    if (!outputFormat) { 
     zj_printf("av_guess_format -> fail\n"); 
     return -1; 
    } 
    outputFormat->video_codec = AV_CODEC_ID_H264; 

    avformat_alloc_output_context2(&formatContext, NULL, NULL, fileName); 
    if (!formatContext) { 
     zj_printf("avformat_alloc_context -> fail\n"); 
     return -2; 
    } 
    formatContext->oformat = outputFormat; 
    strcpy(formatContext->filename, fileName); 

    video_st = add_video_stream(formatContext, outputFormat, width, height); 
    if (!video_st || open_video(formatContext, video_st)) { 
     zj_printf("Could not open video codec\n"); 
     return -3; 
    } 

    av_dump_format(formatContext, 0, fileName, 1); 
    if (!(outputFormat->flags & AVFMT_NOFILE)) { 
     if (avio_open(&formatContext->pb, fileName, AVIO_FLAG_READ_WRITE) < 0) { 
      zj_printf("could not open file: %s\n", fileName); 
      return -7; 
     } 
    } 

    /* write the stream header, if any */ 
    if (avformat_write_header(formatContext, NULL)) { 
     zj_printf("avformat_write_header -> fail\n"); 
    } 

    return 0; 
} 

добавить видео поток и открытый

static AVStream * add_video_stream(AVFormatContext *pFormatContext, AVOutputFormat *pOutputFormat, int wight, int height) { 

    AVStream *stream = avformat_new_stream(pFormatContext, NULL); 
    if (!stream) { 
     zj_fprintf(stderr, "Could not alloc stream\n"); 
     return NULL; 
    } 
    stream->id = 0; 

    AVCodecContext *codecContext = stream->codec; 
    codecContext->codec_id = pOutputFormat->video_codec; 
    codecContext->codec_type = AVMEDIA_TYPE_VIDEO; 

    /* resolution must be a multiple of two */ 
    codecContext->width = wight; 
    codecContext->height = height; 
    /* time base: this is the fundamental unit of time (in seconds) in terms 
    of which frame timestamps are represented. for fixed-fps content, 
    timebase should be 1/framerate and timestamp increments should be 
    identically 1. */ 
    if (wight==1280 && height == 720) { 
     codecContext->bit_rate = 512000; 
     STREAM_FRAME_RATE = 15; 
    } else { 
     codecContext->bit_rate = 384000; 
     STREAM_FRAME_RATE = 20; 
    } 
    codecContext->time_base = (AVRational){1,STREAM_FRAME_RATE}; 
    stream->time_base = (AVRational){1,STREAM_FRAME_RATE}; 
    codecContext->max_b_frames = 0; 
    codecContext->pix_fmt = AV_PIX_FMT_YUV420P; 
    // these are the encoding params, here we do not need them 
    // codecContext->gop_size = 12; //10 
    // codecContext->me_range = 16; 
    // codecContext->max_qdiff = 4; 
    // codecContext->qmin = 10; 
    // codecContext->qmax = 31; 

    if (pFormatContext->oformat->flags & AVFMT_GLOBALHEADER) 
     codecContext->flags |= CODEC_FLAG_GLOBAL_HEADER; 

    return stream; 
} 

static int open_video(AVFormatContext *pFormatContext, AVStream *pStream) { 
    /* find the video encoder */ 
    AVCodec *codec = avcodec_find_encoder(pStream->codec->codec_id); 
    if (!codec) { 
     return -1; 
    } 

    /* open the codec */ 
    if (avcodec_open2(pStream->codec, codec, NULL)) { 
     return -2; 
    } 

    return 0; 
} 

записи видеокадров

static int write_video_frame(char *buffer, int size) { 
    int ret = 0; 

    if (size > 0) { 
     AVPacket mAVPacket; 
     av_init_packet(&mAVPacket); 
     mAVPacket.flags = isIFrame(buffer, size); 
     mAVPacket.stream_index = video_st->index; 

     mAVPacket.data = buffer; 
     mAVPacket.size = size; 
     mAVPacket.pts = video_PTS; 
     mAVPacket.dts = video_PTS; 
     video_PTS += 1; 

     mAVPacket.pts = av_rescale_q_rnd(mAVPacket.pts, video_st->codec->time_base, video_st->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); 
     mAVPacket.dts = av_rescale_q_rnd(mAVPacket.dts, video_st->codec->time_base, video_st->time_base, (AV_ROUND_NEAR_INF|AV_ROUND_PASS_MINMAX)); 
     mAVPacket.duration = 0; 
     mAVPacket.pos = -1; 

     ret = av_interleaved_write_frame(formatContext, &mAVPacket); 
     } 

     av_packet_unref(&mAVPacket); 


    } else { 
     ret = -2; 
    } 

    if (ret != 0) { 
     zj_printf("av_write_frame error:%d\n", ret); 
    } 

    return ret; 
} 

установить ExtraData в контексте кодека

unsigned char sps_pps[23] = {0x00, 0x00, 0x00, 0x01, 0x67, 0x64, 0x00, 0x29, 0xac, 0x1b, 0x1a, 0xc1, 0xe0, 0x51, 0x90, 0x00, 0x00, 0x00, 0x01, 0x68, 0xea, 0x43, 0xcb}; 
codecContext->extradata_size = 23; 
codecContext->extradata = av_malloc(23 + AV_INPUT_BUFFER_PADDING_SIZE); 
if (codecContext->extradata == NULL) { 
    printf("could not av_malloc the video params extradata!\n"); 
    return -1; 
} 
memcpy(codecContext->extradata, sps_pps, 23); 

ответ

0

Формат битового потока - это приложение b. Вы должны преобразовать в формат MP4, заменив начальные коды на значения длины nal. Вы также должны заполнить extradata в codeccontext. Possible Locations for Sequence/Picture Parameter Set(s) for H.264 Stream

+0

Большое спасибо! Согласно вашему ответу, я просто заполняю extradata в контексте кодека. И теперь все отлично! Я опубликую, что «заполняет extradata». –

+0

Контекст кодека имеет переменную calld extradata (и размер extradata), которая просто устанавливает это, чтобы указать на структуру, описанную в этом сообщении. – szatmary

 Смежные вопросы

  • Нет связанных вопросов^_^