正在显示
2 个修改的文件
包含
693 行增加
和
693 行删除
| @@ -858,231 +858,622 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* | @@ -858,231 +858,622 @@ int srs_rtmp_write_packet(srs_rtmp_t rtmp, char type, u_int32_t timestamp, char* | ||
| 858 | return ret; | 858 | return ret; |
| 859 | } | 859 | } |
| 860 | 860 | ||
| 861 | -struct FlvContext | ||
| 862 | -{ | ||
| 863 | - SrsFileReader reader; | ||
| 864 | - SrsFileWriter writer; | ||
| 865 | - SrsFlvEncoder enc; | ||
| 866 | - SrsFlvDecoder dec; | ||
| 867 | -}; | 861 | +/** |
| 862 | +* write audio raw frame to SRS. | ||
| 863 | +*/ | ||
| 864 | +int srs_audio_write_raw_frame(srs_rtmp_t rtmp, | ||
| 865 | + char sound_format, char sound_rate, char sound_size, char sound_type, | ||
| 866 | + char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp | ||
| 867 | +) { | ||
| 868 | + Context* context = (Context*)rtmp; | ||
| 869 | + srs_assert(context); | ||
| 868 | 870 | ||
| 869 | -srs_flv_t srs_flv_open_read(const char* file) | ||
| 870 | -{ | ||
| 871 | - int ret = ERROR_SUCCESS; | ||
| 872 | - | ||
| 873 | - FlvContext* flv = new FlvContext(); | ||
| 874 | - | ||
| 875 | - if ((ret = flv->reader.open(file)) != ERROR_SUCCESS) { | ||
| 876 | - srs_freep(flv); | ||
| 877 | - return NULL; | ||
| 878 | - } | 871 | + // TODO: FIXME: for aac, must send the sequence header first. |
| 879 | 872 | ||
| 880 | - if ((ret = flv->dec.initialize(&flv->reader)) != ERROR_SUCCESS) { | ||
| 881 | - srs_freep(flv); | ||
| 882 | - return NULL; | 873 | + // for audio frame, there is 1 or 2 bytes header: |
| 874 | + // 1bytes, SoundFormat|SoundRate|SoundSize|SoundType | ||
| 875 | + // 1bytes, AACPacketType for SoundFormat == 10 | ||
| 876 | + int size = frame_size + 1; | ||
| 877 | + if (aac_packet_type == SrsCodecAudioAAC) { | ||
| 878 | + size += 1; | ||
| 883 | } | 879 | } |
| 880 | + char* data = new char[size]; | ||
| 881 | + char* p = data; | ||
| 884 | 882 | ||
| 885 | - return flv; | ||
| 886 | -} | ||
| 887 | - | ||
| 888 | -srs_flv_t srs_flv_open_write(const char* file) | ||
| 889 | -{ | ||
| 890 | - int ret = ERROR_SUCCESS; | 883 | + u_int8_t audio_header = sound_type & 0x01; |
| 884 | + audio_header |= (sound_size << 1) & 0x02; | ||
| 885 | + audio_header |= (sound_rate << 2) & 0x0c; | ||
| 886 | + audio_header |= (sound_format << 4) & 0xf0; | ||
| 891 | 887 | ||
| 892 | - FlvContext* flv = new FlvContext(); | 888 | + *p++ = audio_header; |
| 893 | 889 | ||
| 894 | - if ((ret = flv->writer.open(file)) != ERROR_SUCCESS) { | ||
| 895 | - srs_freep(flv); | ||
| 896 | - return NULL; | 890 | + if (aac_packet_type == SrsCodecAudioAAC) { |
| 891 | + *p++ = aac_packet_type; | ||
| 897 | } | 892 | } |
| 898 | 893 | ||
| 899 | - if ((ret = flv->enc.initialize(&flv->writer)) != ERROR_SUCCESS) { | ||
| 900 | - srs_freep(flv); | ||
| 901 | - return NULL; | ||
| 902 | - } | 894 | + memcpy(p, frame, frame_size); |
| 903 | 895 | ||
| 904 | - return flv; | ||
| 905 | -} | ||
| 906 | - | ||
| 907 | -void srs_flv_close(srs_flv_t flv) | ||
| 908 | -{ | ||
| 909 | - FlvContext* context = (FlvContext*)flv; | ||
| 910 | - srs_freep(context); | 896 | + return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); |
| 911 | } | 897 | } |
| 912 | 898 | ||
| 913 | -int srs_flv_read_header(srs_flv_t flv, char header[9]) | ||
| 914 | -{ | ||
| 915 | - int ret = ERROR_SUCCESS; | 899 | +/** |
| 900 | +* write h264 packet, with rtmp header. | ||
| 901 | +* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame. | ||
| 902 | +* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU. | ||
| 903 | +* @param h264_raw_data the h.264 raw data, user must free it. | ||
| 904 | +*/ | ||
| 905 | +int __srs_write_h264_packet(Context* context, | ||
| 906 | + int8_t frame_type, int8_t avc_packet_type, | ||
| 907 | + char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts | ||
| 908 | +) { | ||
| 909 | + // the timestamp in rtmp message header is dts. | ||
| 910 | + u_int32_t timestamp = dts; | ||
| 916 | 911 | ||
| 917 | - FlvContext* context = (FlvContext*)flv; | ||
| 918 | - | ||
| 919 | - if (!context->reader.is_open()) { | ||
| 920 | - return ERROR_SYSTEM_IO_INVALID; | ||
| 921 | - } | 912 | + // for h264 in RTMP video payload, there is 5bytes header: |
| 913 | + // 1bytes, FrameType | CodecID | ||
| 914 | + // 1bytes, AVCPacketType | ||
| 915 | + // 3bytes, CompositionTime, the cts. | ||
| 916 | + // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
| 917 | + int size = h264_raw_size + 5; | ||
| 918 | + char* data = new char[size]; | ||
| 919 | + char* p = data; | ||
| 922 | 920 | ||
| 923 | - if ((ret = context->dec.read_header(header)) != ERROR_SUCCESS) { | ||
| 924 | - return ret; | ||
| 925 | - } | 921 | + // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 |
| 922 | + // Frame Type, Type of video frame. | ||
| 923 | + // CodecID, Codec Identifier. | ||
| 924 | + // set the rtmp header | ||
| 925 | + *p++ = (frame_type << 4) | SrsCodecVideoAVC; | ||
| 926 | 926 | ||
| 927 | - char ts[4]; // tag size | ||
| 928 | - if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 929 | - return ret; | ||
| 930 | - } | 927 | + // AVCPacketType |
| 928 | + *p++ = avc_packet_type; | ||
| 929 | + | ||
| 930 | + // CompositionTime | ||
| 931 | + // pts = dts + cts, or | ||
| 932 | + // cts = pts - dts. | ||
| 933 | + // where cts is the header in rtmp video packet payload header. | ||
| 934 | + u_int32_t cts = pts - dts; | ||
| 935 | + char* pp = (char*)&cts; | ||
| 936 | + *p++ = pp[2]; | ||
| 937 | + *p++ = pp[1]; | ||
| 938 | + *p++ = pp[0]; | ||
| 931 | 939 | ||
| 932 | - return ret; | 940 | + // h.264 raw data. |
| 941 | + memcpy(p, h264_raw_data, h264_raw_size); | ||
| 942 | + | ||
| 943 | + return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, data, size); | ||
| 933 | } | 944 | } |
| 934 | 945 | ||
| 935 | -int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime) | 946 | +/** |
| 947 | +* write the h264 sps/pps in context over RTMP. | ||
| 948 | +*/ | ||
| 949 | +int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts) | ||
| 936 | { | 950 | { |
| 937 | int ret = ERROR_SUCCESS; | 951 | int ret = ERROR_SUCCESS; |
| 938 | 952 | ||
| 939 | - FlvContext* context = (FlvContext*)flv; | ||
| 940 | - | ||
| 941 | - if (!context->reader.is_open()) { | ||
| 942 | - return ERROR_SYSTEM_IO_INVALID; | 953 | + // only send when both sps and pps changed. |
| 954 | + if (!context->h264_sps_changed || !context->h264_pps_changed) { | ||
| 955 | + return ret; | ||
| 943 | } | 956 | } |
| 944 | 957 | ||
| 945 | - if ((ret = context->dec.read_tag_header(ptype, pdata_size, ptime)) != ERROR_SUCCESS) { | 958 | + // 5bytes sps/pps header: |
| 959 | + // configurationVersion, AVCProfileIndication, profile_compatibility, | ||
| 960 | + // AVCLevelIndication, lengthSizeMinusOne | ||
| 961 | + // 3bytes size of sps: | ||
| 962 | + // numOfSequenceParameterSets, sequenceParameterSetLength(2B) | ||
| 963 | + // Nbytes of sps. | ||
| 964 | + // sequenceParameterSetNALUnit | ||
| 965 | + // 3bytes size of pps: | ||
| 966 | + // numOfPictureParameterSets, pictureParameterSetLength | ||
| 967 | + // Nbytes of pps: | ||
| 968 | + // pictureParameterSetNALUnit | ||
| 969 | + int nb_packet = 5 | ||
| 970 | + + 3 + (int)context->h264_sps.length() | ||
| 971 | + + 3 + (int)context->h264_pps.length(); | ||
| 972 | + char* packet = new char[nb_packet]; | ||
| 973 | + SrsAutoFree(char, packet); | ||
| 974 | + | ||
| 975 | + // use stream to generate the h264 packet. | ||
| 976 | + SrsStream stream; | ||
| 977 | + if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 946 | return ret; | 978 | return ret; |
| 947 | } | 979 | } |
| 948 | 980 | ||
| 949 | - return ret; | ||
| 950 | -} | ||
| 951 | - | ||
| 952 | -int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) | ||
| 953 | -{ | ||
| 954 | - int ret = ERROR_SUCCESS; | 981 | + // decode the SPS: |
| 982 | + // @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | ||
| 983 | + if (true) { | ||
| 984 | + srs_assert((int)context->h264_sps.length() >= 4); | ||
| 985 | + char* frame = (char*)context->h264_sps.data(); | ||
| 955 | 986 | ||
| 956 | - FlvContext* context = (FlvContext*)flv; | ||
| 957 | - | ||
| 958 | - if (!context->reader.is_open()) { | ||
| 959 | - return ERROR_SYSTEM_IO_INVALID; | 987 | + // @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205 |
| 988 | + // Baseline profile profile_idc is 66(0x42). | ||
| 989 | + // Main profile profile_idc is 77(0x4d). | ||
| 990 | + // Extended profile profile_idc is 88(0x58). | ||
| 991 | + u_int8_t profile_idc = frame[1]; | ||
| 992 | + //u_int8_t constraint_set = frame[2]; | ||
| 993 | + u_int8_t level_idc = frame[3]; | ||
| 994 | + | ||
| 995 | + // generate the sps/pps header | ||
| 996 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 997 | + // configurationVersion | ||
| 998 | + stream.write_1bytes(0x01); | ||
| 999 | + // AVCProfileIndication | ||
| 1000 | + stream.write_1bytes(profile_idc); | ||
| 1001 | + // profile_compatibility | ||
| 1002 | + stream.write_1bytes(0x00); | ||
| 1003 | + // AVCLevelIndication | ||
| 1004 | + stream.write_1bytes(level_idc); | ||
| 1005 | + // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size, | ||
| 1006 | + // so we always set it to 0x03. | ||
| 1007 | + stream.write_1bytes(0x03); | ||
| 960 | } | 1008 | } |
| 961 | 1009 | ||
| 962 | - if ((ret = context->dec.read_tag_data(data, size)) != ERROR_SUCCESS) { | ||
| 963 | - return ret; | 1010 | + // sps |
| 1011 | + if (true) { | ||
| 1012 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1013 | + // numOfSequenceParameterSets, always 1 | ||
| 1014 | + stream.write_1bytes(0x01); | ||
| 1015 | + // sequenceParameterSetLength | ||
| 1016 | + stream.write_2bytes(context->h264_sps.length()); | ||
| 1017 | + // sequenceParameterSetNALUnit | ||
| 1018 | + stream.write_string(context->h264_sps); | ||
| 964 | } | 1019 | } |
| 965 | 1020 | ||
| 966 | - char ts[4]; // tag size | ||
| 967 | - if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 968 | - return ret; | 1021 | + // pps |
| 1022 | + if (true) { | ||
| 1023 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1024 | + // numOfPictureParameterSets, always 1 | ||
| 1025 | + stream.write_1bytes(0x01); | ||
| 1026 | + // pictureParameterSetLength | ||
| 1027 | + stream.write_2bytes(context->h264_pps.length()); | ||
| 1028 | + // pictureParameterSetNALUnit | ||
| 1029 | + stream.write_string(context->h264_pps); | ||
| 969 | } | 1030 | } |
| 970 | 1031 | ||
| 971 | - return ret; | ||
| 972 | -} | ||
| 973 | - | ||
| 974 | -int srs_flv_write_header(srs_flv_t flv, char header[9]) | ||
| 975 | -{ | ||
| 976 | - int ret = ERROR_SUCCESS; | ||
| 977 | - | ||
| 978 | - FlvContext* context = (FlvContext*)flv; | ||
| 979 | - | ||
| 980 | - if (!context->writer.is_open()) { | ||
| 981 | - return ERROR_SYSTEM_IO_INVALID; | ||
| 982 | - } | 1032 | + // reset sps and pps. |
| 1033 | + context->h264_sps_changed = false; | ||
| 1034 | + context->h264_pps_changed = false; | ||
| 1035 | + context->h264_sps_pps_sent = true; | ||
| 983 | 1036 | ||
| 984 | - if ((ret = context->enc.write_header(header)) != ERROR_SUCCESS) { | ||
| 985 | - return ret; | ||
| 986 | - } | 1037 | + // TODO: FIXME: for more profile. |
| 1038 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1039 | + // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 | ||
| 987 | 1040 | ||
| 988 | - return ret; | 1041 | + // send out h264 packet. |
| 1042 | + int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1043 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; | ||
| 1044 | + return __srs_write_h264_packet( | ||
| 1045 | + context, frame_type, avc_packet_type, | ||
| 1046 | + packet, nb_packet, dts, pts | ||
| 1047 | + ); | ||
| 989 | } | 1048 | } |
| 990 | 1049 | ||
| 991 | -int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) | ||
| 992 | -{ | 1050 | +/** |
| 1051 | +* write h264 IPB-frame. | ||
| 1052 | +*/ | ||
| 1053 | +int __srs_write_h264_ipb_frame(Context* context, | ||
| 1054 | + char* data, int size, u_int32_t dts, u_int32_t pts | ||
| 1055 | +) { | ||
| 993 | int ret = ERROR_SUCCESS; | 1056 | int ret = ERROR_SUCCESS; |
| 994 | 1057 | ||
| 995 | - FlvContext* context = (FlvContext*)flv; | 1058 | + // when sps or pps not sent, ignore the packet. |
| 1059 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1060 | + if (!context->h264_sps_pps_sent) { | ||
| 1061 | + return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
| 1062 | + } | ||
| 1063 | + | ||
| 1064 | + // 5bits, 7.3.1 NAL unit syntax, | ||
| 1065 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1066 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1067 | + u_int8_t nal_unit_type = (char)data[0] & 0x1f; | ||
| 1068 | + | ||
| 1069 | + // 4bytes size of nalu: | ||
| 1070 | + // NALUnitLength | ||
| 1071 | + // Nbytes of nalu. | ||
| 1072 | + // NALUnit | ||
| 1073 | + int nb_packet = 4 + size; | ||
| 1074 | + char* packet = new char[nb_packet]; | ||
| 1075 | + SrsAutoFree(char, packet); | ||
| 1076 | + | ||
| 1077 | + // use stream to generate the h264 packet. | ||
| 1078 | + SrsStream stream; | ||
| 1079 | + if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 1080 | + return ret; | ||
| 1081 | + } | ||
| 996 | 1082 | ||
| 997 | - if (!context->writer.is_open()) { | ||
| 998 | - return ERROR_SYSTEM_IO_INVALID; | 1083 | + // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 |
| 1084 | + // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size | ||
| 1085 | + u_int32_t NAL_unit_length = size; | ||
| 1086 | + | ||
| 1087 | + // mux the avc NALU in "ISO Base Media File Format" | ||
| 1088 | + // from H.264-AVC-ISO_IEC_14496-15.pdf, page 20 | ||
| 1089 | + // NALUnitLength | ||
| 1090 | + stream.write_4bytes(NAL_unit_length); | ||
| 1091 | + // NALUnit | ||
| 1092 | + stream.write_bytes(data, size); | ||
| 1093 | + | ||
| 1094 | + // send out h264 packet. | ||
| 1095 | + int8_t frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
| 1096 | + if (nal_unit_type != 1) { | ||
| 1097 | + frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 999 | } | 1098 | } |
| 1099 | + int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | ||
| 1100 | + return __srs_write_h264_packet( | ||
| 1101 | + context, frame_type, avc_packet_type, | ||
| 1102 | + packet, nb_packet, dts, pts | ||
| 1103 | + ); | ||
| 1000 | 1104 | ||
| 1001 | - if (type == SRS_RTMP_TYPE_AUDIO) { | ||
| 1002 | - return context->enc.write_audio(time, data, size); | ||
| 1003 | - } else if (type == SRS_RTMP_TYPE_VIDEO) { | ||
| 1004 | - return context->enc.write_video(time, data, size); | 1105 | + return ret; |
| 1106 | +} | ||
| 1107 | + | ||
| 1108 | +/** | ||
| 1109 | +* write h264 raw frame, maybe sps/pps/IPB-frame. | ||
| 1110 | +*/ | ||
| 1111 | +int __srs_write_h264_raw_frame(Context* context, | ||
| 1112 | + char* frame, int frame_size, u_int32_t dts, u_int32_t pts | ||
| 1113 | +) { | ||
| 1114 | + int ret = ERROR_SUCCESS; | ||
| 1115 | + | ||
| 1116 | + // ignore invalid frame, | ||
| 1117 | + // atleast 1bytes for SPS to decode the type | ||
| 1118 | + if (frame_size < 1) { | ||
| 1119 | + return ret; | ||
| 1120 | + } | ||
| 1121 | + | ||
| 1122 | + // 5bits, 7.3.1 NAL unit syntax, | ||
| 1123 | + // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1124 | + // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1125 | + u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
| 1126 | + | ||
| 1127 | + if (nal_unit_type == 7) { | ||
| 1128 | + // atleast 1bytes for SPS to decode the type, profile, constrain and level. | ||
| 1129 | + if (frame_size < 4) { | ||
| 1130 | + return ret; | ||
| 1131 | + } | ||
| 1132 | + | ||
| 1133 | + std::string sps; | ||
| 1134 | + sps.append(frame, frame_size); | ||
| 1135 | + | ||
| 1136 | + if (context->h264_sps == sps) { | ||
| 1137 | + return ERROR_H264_DUPLICATED_SPS; | ||
| 1138 | + } | ||
| 1139 | + context->h264_sps_changed = true; | ||
| 1140 | + context->h264_sps = sps; | ||
| 1141 | + | ||
| 1142 | + return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1143 | + } else if (nal_unit_type == 8) { | ||
| 1144 | + | ||
| 1145 | + std::string pps; | ||
| 1146 | + pps.append(frame, frame_size); | ||
| 1147 | + | ||
| 1148 | + if (context->h264_pps == pps) { | ||
| 1149 | + return ERROR_H264_DUPLICATED_PPS; | ||
| 1150 | + } | ||
| 1151 | + context->h264_pps_changed = true; | ||
| 1152 | + context->h264_pps = pps; | ||
| 1153 | + | ||
| 1154 | + return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1005 | } else { | 1155 | } else { |
| 1006 | - return context->enc.write_metadata(data, size); | 1156 | + return __srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); |
| 1007 | } | 1157 | } |
| 1008 | - | 1158 | + |
| 1009 | return ret; | 1159 | return ret; |
| 1010 | } | 1160 | } |
| 1011 | 1161 | ||
| 1012 | -int srs_flv_size_tag(int data_size) | ||
| 1013 | -{ | ||
| 1014 | - return SrsFlvEncoder::size_tag(data_size); | 1162 | +/** |
| 1163 | +* write h264 multiple frames, in annexb format. | ||
| 1164 | +*/ | ||
| 1165 | +int srs_h264_write_raw_frames(srs_rtmp_t rtmp, | ||
| 1166 | + char* frames, int frames_size, u_int32_t dts, u_int32_t pts | ||
| 1167 | +) { | ||
| 1168 | + int ret = ERROR_SUCCESS; | ||
| 1169 | + | ||
| 1170 | + srs_assert(frames != NULL); | ||
| 1171 | + srs_assert(frames_size > 0); | ||
| 1172 | + | ||
| 1173 | + srs_assert(rtmp != NULL); | ||
| 1174 | + Context* context = (Context*)rtmp; | ||
| 1175 | + | ||
| 1176 | + if ((ret = context->h264_raw_stream.initialize(frames, frames_size)) != ERROR_SUCCESS) { | ||
| 1177 | + return ret; | ||
| 1178 | + } | ||
| 1179 | + | ||
| 1180 | + // use the last error | ||
| 1181 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1182 | + // @see https://github.com/winlinvip/simple-rtmp-server/issues/204 | ||
| 1183 | + int error_code_return = ret; | ||
| 1184 | + | ||
| 1185 | + // send each frame. | ||
| 1186 | + while (!context->h264_raw_stream.empty()) { | ||
| 1187 | + // each frame must prefixed by annexb format. | ||
| 1188 | + // about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | ||
| 1189 | + int pnb_start_code = 0; | ||
| 1190 | + if (!srs_avc_startswith_annexb(&context->h264_raw_stream, &pnb_start_code)) { | ||
| 1191 | + return ERROR_H264_API_NO_PREFIXED; | ||
| 1192 | + } | ||
| 1193 | + int start = context->h264_raw_stream.pos() + pnb_start_code; | ||
| 1194 | + | ||
| 1195 | + // find the last frame prefixed by annexb format. | ||
| 1196 | + context->h264_raw_stream.skip(pnb_start_code); | ||
| 1197 | + while (!context->h264_raw_stream.empty()) { | ||
| 1198 | + if (srs_avc_startswith_annexb(&context->h264_raw_stream, NULL)) { | ||
| 1199 | + break; | ||
| 1200 | + } | ||
| 1201 | + context->h264_raw_stream.skip(1); | ||
| 1202 | + } | ||
| 1203 | + int size = context->h264_raw_stream.pos() - start; | ||
| 1204 | + | ||
| 1205 | + // send out the frame. | ||
| 1206 | + char* frame = context->h264_raw_stream.data() + start; | ||
| 1207 | + | ||
| 1208 | + // it may be return error, but we must process all packets. | ||
| 1209 | + if ((ret = __srs_write_h264_raw_frame(context, frame, size, dts, pts)) != ERROR_SUCCESS) { | ||
| 1210 | + error_code_return = ret; | ||
| 1211 | + | ||
| 1212 | + // ignore known error, process all packets. | ||
| 1213 | + if (srs_h264_is_dvbsp_error(ret) | ||
| 1214 | + || srs_h264_is_duplicated_sps_error(ret) | ||
| 1215 | + || srs_h264_is_duplicated_pps_error(ret) | ||
| 1216 | + ) { | ||
| 1217 | + continue; | ||
| 1218 | + } | ||
| 1219 | + | ||
| 1220 | + return ret; | ||
| 1221 | + } | ||
| 1222 | + } | ||
| 1223 | + | ||
| 1224 | + return error_code_return; | ||
| 1015 | } | 1225 | } |
| 1016 | 1226 | ||
| 1017 | -int64_t srs_flv_tellg(srs_flv_t flv) | 1227 | +srs_h264_bool srs_h264_is_dvbsp_error(int error_code) |
| 1018 | { | 1228 | { |
| 1019 | - FlvContext* context = (FlvContext*)flv; | ||
| 1020 | - return context->reader.tellg(); | 1229 | + return error_code == ERROR_H264_DROP_BEFORE_SPS_PPS; |
| 1021 | } | 1230 | } |
| 1022 | 1231 | ||
| 1023 | -void srs_flv_lseek(srs_flv_t flv, int64_t offset) | 1232 | +srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code) |
| 1024 | { | 1233 | { |
| 1025 | - FlvContext* context = (FlvContext*)flv; | ||
| 1026 | - context->reader.lseek(offset); | 1234 | + return error_code == ERROR_H264_DUPLICATED_SPS; |
| 1027 | } | 1235 | } |
| 1028 | 1236 | ||
| 1029 | -srs_flv_bool srs_flv_is_eof(int error_code) | 1237 | +srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code) |
| 1030 | { | 1238 | { |
| 1031 | - return error_code == ERROR_SYSTEM_FILE_EOF; | 1239 | + return error_code == ERROR_H264_DUPLICATED_PPS; |
| 1032 | } | 1240 | } |
| 1033 | 1241 | ||
| 1034 | -srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size) | 1242 | +int srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code) |
| 1035 | { | 1243 | { |
| 1036 | - return SrsFlvCodec::video_is_sequence_header(data, (int)size); | 1244 | + SrsStream stream; |
| 1245 | + if (stream.initialize(h264_raw_data, h264_raw_size) != ERROR_SUCCESS) { | ||
| 1246 | + return false; | ||
| 1247 | + } | ||
| 1248 | + | ||
| 1249 | + return srs_avc_startswith_annexb(&stream, pnb_start_code); | ||
| 1037 | } | 1250 | } |
| 1038 | 1251 | ||
| 1039 | -srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size) | 1252 | +struct FlvContext |
| 1040 | { | 1253 | { |
| 1041 | - return SrsFlvCodec::video_is_keyframe(data, (int)size); | ||
| 1042 | -} | 1254 | + SrsFileReader reader; |
| 1255 | + SrsFileWriter writer; | ||
| 1256 | + SrsFlvEncoder enc; | ||
| 1257 | + SrsFlvDecoder dec; | ||
| 1258 | +}; | ||
| 1043 | 1259 | ||
| 1044 | -srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) | 1260 | +srs_flv_t srs_flv_open_read(const char* file) |
| 1045 | { | 1261 | { |
| 1046 | int ret = ERROR_SUCCESS; | 1262 | int ret = ERROR_SUCCESS; |
| 1047 | 1263 | ||
| 1048 | - srs_amf0_t amf0 = NULL; | 1264 | + FlvContext* flv = new FlvContext(); |
| 1049 | 1265 | ||
| 1050 | - SrsStream stream; | ||
| 1051 | - if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { | ||
| 1052 | - return amf0; | 1266 | + if ((ret = flv->reader.open(file)) != ERROR_SUCCESS) { |
| 1267 | + srs_freep(flv); | ||
| 1268 | + return NULL; | ||
| 1053 | } | 1269 | } |
| 1054 | 1270 | ||
| 1055 | - SrsAmf0Any* any = NULL; | ||
| 1056 | - if ((ret = SrsAmf0Any::discovery(&stream, &any)) != ERROR_SUCCESS) { | ||
| 1057 | - return amf0; | 1271 | + if ((ret = flv->dec.initialize(&flv->reader)) != ERROR_SUCCESS) { |
| 1272 | + srs_freep(flv); | ||
| 1273 | + return NULL; | ||
| 1058 | } | 1274 | } |
| 1059 | 1275 | ||
| 1060 | - stream.skip(-1 * stream.pos()); | ||
| 1061 | - if ((ret = any->read(&stream)) != ERROR_SUCCESS) { | ||
| 1062 | - srs_freep(any); | ||
| 1063 | - return amf0; | 1276 | + return flv; |
| 1277 | +} | ||
| 1278 | + | ||
| 1279 | +srs_flv_t srs_flv_open_write(const char* file) | ||
| 1280 | +{ | ||
| 1281 | + int ret = ERROR_SUCCESS; | ||
| 1282 | + | ||
| 1283 | + FlvContext* flv = new FlvContext(); | ||
| 1284 | + | ||
| 1285 | + if ((ret = flv->writer.open(file)) != ERROR_SUCCESS) { | ||
| 1286 | + srs_freep(flv); | ||
| 1287 | + return NULL; | ||
| 1064 | } | 1288 | } |
| 1065 | 1289 | ||
| 1066 | - if (nparsed) { | ||
| 1067 | - *nparsed = stream.pos(); | 1290 | + if ((ret = flv->enc.initialize(&flv->writer)) != ERROR_SUCCESS) { |
| 1291 | + srs_freep(flv); | ||
| 1292 | + return NULL; | ||
| 1068 | } | 1293 | } |
| 1069 | - amf0 = (srs_amf0_t)any; | ||
| 1070 | 1294 | ||
| 1071 | - return amf0; | 1295 | + return flv; |
| 1072 | } | 1296 | } |
| 1073 | 1297 | ||
| 1074 | -srs_amf0_t srs_amf0_create_number(srs_amf0_number value) | 1298 | +void srs_flv_close(srs_flv_t flv) |
| 1075 | { | 1299 | { |
| 1076 | - return SrsAmf0Any::number(value); | 1300 | + FlvContext* context = (FlvContext*)flv; |
| 1301 | + srs_freep(context); | ||
| 1077 | } | 1302 | } |
| 1078 | 1303 | ||
| 1079 | -srs_amf0_t srs_amf0_create_ecma_array() | 1304 | +int srs_flv_read_header(srs_flv_t flv, char header[9]) |
| 1080 | { | 1305 | { |
| 1081 | - return SrsAmf0Any::ecma_array(); | ||
| 1082 | -} | 1306 | + int ret = ERROR_SUCCESS; |
| 1307 | + | ||
| 1308 | + FlvContext* context = (FlvContext*)flv; | ||
| 1083 | 1309 | ||
| 1084 | -srs_amf0_t srs_amf0_create_strict_array() | ||
| 1085 | -{ | 1310 | + if (!context->reader.is_open()) { |
| 1311 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1312 | + } | ||
| 1313 | + | ||
| 1314 | + if ((ret = context->dec.read_header(header)) != ERROR_SUCCESS) { | ||
| 1315 | + return ret; | ||
| 1316 | + } | ||
| 1317 | + | ||
| 1318 | + char ts[4]; // tag size | ||
| 1319 | + if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 1320 | + return ret; | ||
| 1321 | + } | ||
| 1322 | + | ||
| 1323 | + return ret; | ||
| 1324 | +} | ||
| 1325 | + | ||
| 1326 | +int srs_flv_read_tag_header(srs_flv_t flv, char* ptype, int32_t* pdata_size, u_int32_t* ptime) | ||
| 1327 | +{ | ||
| 1328 | + int ret = ERROR_SUCCESS; | ||
| 1329 | + | ||
| 1330 | + FlvContext* context = (FlvContext*)flv; | ||
| 1331 | + | ||
| 1332 | + if (!context->reader.is_open()) { | ||
| 1333 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1334 | + } | ||
| 1335 | + | ||
| 1336 | + if ((ret = context->dec.read_tag_header(ptype, pdata_size, ptime)) != ERROR_SUCCESS) { | ||
| 1337 | + return ret; | ||
| 1338 | + } | ||
| 1339 | + | ||
| 1340 | + return ret; | ||
| 1341 | +} | ||
| 1342 | + | ||
| 1343 | +int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size) | ||
| 1344 | +{ | ||
| 1345 | + int ret = ERROR_SUCCESS; | ||
| 1346 | + | ||
| 1347 | + FlvContext* context = (FlvContext*)flv; | ||
| 1348 | + | ||
| 1349 | + if (!context->reader.is_open()) { | ||
| 1350 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1351 | + } | ||
| 1352 | + | ||
| 1353 | + if ((ret = context->dec.read_tag_data(data, size)) != ERROR_SUCCESS) { | ||
| 1354 | + return ret; | ||
| 1355 | + } | ||
| 1356 | + | ||
| 1357 | + char ts[4]; // tag size | ||
| 1358 | + if ((ret = context->dec.read_previous_tag_size(ts)) != ERROR_SUCCESS) { | ||
| 1359 | + return ret; | ||
| 1360 | + } | ||
| 1361 | + | ||
| 1362 | + return ret; | ||
| 1363 | +} | ||
| 1364 | + | ||
| 1365 | +int srs_flv_write_header(srs_flv_t flv, char header[9]) | ||
| 1366 | +{ | ||
| 1367 | + int ret = ERROR_SUCCESS; | ||
| 1368 | + | ||
| 1369 | + FlvContext* context = (FlvContext*)flv; | ||
| 1370 | + | ||
| 1371 | + if (!context->writer.is_open()) { | ||
| 1372 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1373 | + } | ||
| 1374 | + | ||
| 1375 | + if ((ret = context->enc.write_header(header)) != ERROR_SUCCESS) { | ||
| 1376 | + return ret; | ||
| 1377 | + } | ||
| 1378 | + | ||
| 1379 | + return ret; | ||
| 1380 | +} | ||
| 1381 | + | ||
| 1382 | +int srs_flv_write_tag(srs_flv_t flv, char type, int32_t time, char* data, int size) | ||
| 1383 | +{ | ||
| 1384 | + int ret = ERROR_SUCCESS; | ||
| 1385 | + | ||
| 1386 | + FlvContext* context = (FlvContext*)flv; | ||
| 1387 | + | ||
| 1388 | + if (!context->writer.is_open()) { | ||
| 1389 | + return ERROR_SYSTEM_IO_INVALID; | ||
| 1390 | + } | ||
| 1391 | + | ||
| 1392 | + if (type == SRS_RTMP_TYPE_AUDIO) { | ||
| 1393 | + return context->enc.write_audio(time, data, size); | ||
| 1394 | + } else if (type == SRS_RTMP_TYPE_VIDEO) { | ||
| 1395 | + return context->enc.write_video(time, data, size); | ||
| 1396 | + } else { | ||
| 1397 | + return context->enc.write_metadata(data, size); | ||
| 1398 | + } | ||
| 1399 | + | ||
| 1400 | + return ret; | ||
| 1401 | +} | ||
| 1402 | + | ||
| 1403 | +int srs_flv_size_tag(int data_size) | ||
| 1404 | +{ | ||
| 1405 | + return SrsFlvEncoder::size_tag(data_size); | ||
| 1406 | +} | ||
| 1407 | + | ||
| 1408 | +int64_t srs_flv_tellg(srs_flv_t flv) | ||
| 1409 | +{ | ||
| 1410 | + FlvContext* context = (FlvContext*)flv; | ||
| 1411 | + return context->reader.tellg(); | ||
| 1412 | +} | ||
| 1413 | + | ||
| 1414 | +void srs_flv_lseek(srs_flv_t flv, int64_t offset) | ||
| 1415 | +{ | ||
| 1416 | + FlvContext* context = (FlvContext*)flv; | ||
| 1417 | + context->reader.lseek(offset); | ||
| 1418 | +} | ||
| 1419 | + | ||
| 1420 | +srs_flv_bool srs_flv_is_eof(int error_code) | ||
| 1421 | +{ | ||
| 1422 | + return error_code == ERROR_SYSTEM_FILE_EOF; | ||
| 1423 | +} | ||
| 1424 | + | ||
| 1425 | +srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size) | ||
| 1426 | +{ | ||
| 1427 | + return SrsFlvCodec::video_is_sequence_header(data, (int)size); | ||
| 1428 | +} | ||
| 1429 | + | ||
| 1430 | +srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size) | ||
| 1431 | +{ | ||
| 1432 | + return SrsFlvCodec::video_is_keyframe(data, (int)size); | ||
| 1433 | +} | ||
| 1434 | + | ||
| 1435 | +srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed) | ||
| 1436 | +{ | ||
| 1437 | + int ret = ERROR_SUCCESS; | ||
| 1438 | + | ||
| 1439 | + srs_amf0_t amf0 = NULL; | ||
| 1440 | + | ||
| 1441 | + SrsStream stream; | ||
| 1442 | + if ((ret = stream.initialize(data, size)) != ERROR_SUCCESS) { | ||
| 1443 | + return amf0; | ||
| 1444 | + } | ||
| 1445 | + | ||
| 1446 | + SrsAmf0Any* any = NULL; | ||
| 1447 | + if ((ret = SrsAmf0Any::discovery(&stream, &any)) != ERROR_SUCCESS) { | ||
| 1448 | + return amf0; | ||
| 1449 | + } | ||
| 1450 | + | ||
| 1451 | + stream.skip(-1 * stream.pos()); | ||
| 1452 | + if ((ret = any->read(&stream)) != ERROR_SUCCESS) { | ||
| 1453 | + srs_freep(any); | ||
| 1454 | + return amf0; | ||
| 1455 | + } | ||
| 1456 | + | ||
| 1457 | + if (nparsed) { | ||
| 1458 | + *nparsed = stream.pos(); | ||
| 1459 | + } | ||
| 1460 | + amf0 = (srs_amf0_t)any; | ||
| 1461 | + | ||
| 1462 | + return amf0; | ||
| 1463 | +} | ||
| 1464 | + | ||
| 1465 | +srs_amf0_t srs_amf0_create_number(srs_amf0_number value) | ||
| 1466 | +{ | ||
| 1467 | + return SrsAmf0Any::number(value); | ||
| 1468 | +} | ||
| 1469 | + | ||
| 1470 | +srs_amf0_t srs_amf0_create_ecma_array() | ||
| 1471 | +{ | ||
| 1472 | + return SrsAmf0Any::ecma_array(); | ||
| 1473 | +} | ||
| 1474 | + | ||
| 1475 | +srs_amf0_t srs_amf0_create_strict_array() | ||
| 1476 | +{ | ||
| 1086 | return SrsAmf0Any::strict_array(); | 1477 | return SrsAmf0Any::strict_array(); |
| 1087 | } | 1478 | } |
| 1088 | 1479 | ||
| @@ -1321,397 +1712,6 @@ void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) | @@ -1321,397 +1712,6 @@ void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value) | ||
| 1321 | obj->append(any); | 1712 | obj->append(any); |
| 1322 | } | 1713 | } |
| 1323 | 1714 | ||
| 1324 | -/** | ||
| 1325 | -* write audio raw frame to SRS. | ||
| 1326 | -*/ | ||
| 1327 | -int srs_audio_write_raw_frame(srs_rtmp_t rtmp, | ||
| 1328 | - char sound_format, char sound_rate, char sound_size, char sound_type, | ||
| 1329 | - char aac_packet_type, char* frame, int frame_size, u_int32_t timestamp | ||
| 1330 | -) { | ||
| 1331 | - Context* context = (Context*)rtmp; | ||
| 1332 | - srs_assert(context); | ||
| 1333 | - | ||
| 1334 | - // TODO: FIXME: for aac, must send the sequence header first. | ||
| 1335 | - | ||
| 1336 | - // for audio frame, there is 1 or 2 bytes header: | ||
| 1337 | - // 1bytes, SoundFormat|SoundRate|SoundSize|SoundType | ||
| 1338 | - // 1bytes, AACPacketType for SoundFormat == 10 | ||
| 1339 | - int size = frame_size + 1; | ||
| 1340 | - if (aac_packet_type == SrsCodecAudioAAC) { | ||
| 1341 | - size += 1; | ||
| 1342 | - } | ||
| 1343 | - char* data = new char[size]; | ||
| 1344 | - char* p = data; | ||
| 1345 | - | ||
| 1346 | - u_int8_t audio_header = sound_type & 0x01; | ||
| 1347 | - audio_header |= (sound_size << 1) & 0x02; | ||
| 1348 | - audio_header |= (sound_rate << 2) & 0x0c; | ||
| 1349 | - audio_header |= (sound_format << 4) & 0xf0; | ||
| 1350 | - | ||
| 1351 | - *p++ = audio_header; | ||
| 1352 | - | ||
| 1353 | - if (aac_packet_type == SrsCodecAudioAAC) { | ||
| 1354 | - *p++ = aac_packet_type; | ||
| 1355 | - } | ||
| 1356 | - | ||
| 1357 | - memcpy(p, frame, frame_size); | ||
| 1358 | - | ||
| 1359 | - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_AUDIO, timestamp, data, size); | ||
| 1360 | -} | ||
| 1361 | - | ||
| 1362 | -/** | ||
| 1363 | -* write h264 packet, with rtmp header. | ||
| 1364 | -* @param frame_type, SrsCodecVideoAVCFrameKeyFrame or SrsCodecVideoAVCFrameInterFrame. | ||
| 1365 | -* @param avc_packet_type, SrsCodecVideoAVCTypeSequenceHeader or SrsCodecVideoAVCTypeNALU. | ||
| 1366 | -* @param h264_raw_data the h.264 raw data, user must free it. | ||
| 1367 | -*/ | ||
| 1368 | -int __srs_write_h264_packet(Context* context, | ||
| 1369 | - int8_t frame_type, int8_t avc_packet_type, | ||
| 1370 | - char* h264_raw_data, int h264_raw_size, u_int32_t dts, u_int32_t pts | ||
| 1371 | -) { | ||
| 1372 | - // the timestamp in rtmp message header is dts. | ||
| 1373 | - u_int32_t timestamp = dts; | ||
| 1374 | - | ||
| 1375 | - // for h264 in RTMP video payload, there is 5bytes header: | ||
| 1376 | - // 1bytes, FrameType | CodecID | ||
| 1377 | - // 1bytes, AVCPacketType | ||
| 1378 | - // 3bytes, CompositionTime, the cts. | ||
| 1379 | - // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
| 1380 | - int size = h264_raw_size + 5; | ||
| 1381 | - char* data = new char[size]; | ||
| 1382 | - char* p = data; | ||
| 1383 | - | ||
| 1384 | - // @see: E.4.3 Video Tags, video_file_format_spec_v10_1.pdf, page 78 | ||
| 1385 | - // Frame Type, Type of video frame. | ||
| 1386 | - // CodecID, Codec Identifier. | ||
| 1387 | - // set the rtmp header | ||
| 1388 | - *p++ = (frame_type << 4) | SrsCodecVideoAVC; | ||
| 1389 | - | ||
| 1390 | - // AVCPacketType | ||
| 1391 | - *p++ = avc_packet_type; | ||
| 1392 | - | ||
| 1393 | - // CompositionTime | ||
| 1394 | - // pts = dts + cts, or | ||
| 1395 | - // cts = pts - dts. | ||
| 1396 | - // where cts is the header in rtmp video packet payload header. | ||
| 1397 | - u_int32_t cts = pts - dts; | ||
| 1398 | - char* pp = (char*)&cts; | ||
| 1399 | - *p++ = pp[2]; | ||
| 1400 | - *p++ = pp[1]; | ||
| 1401 | - *p++ = pp[0]; | ||
| 1402 | - | ||
| 1403 | - // h.264 raw data. | ||
| 1404 | - memcpy(p, h264_raw_data, h264_raw_size); | ||
| 1405 | - | ||
| 1406 | - return srs_rtmp_write_packet(context, SRS_RTMP_TYPE_VIDEO, timestamp, data, size); | ||
| 1407 | -} | ||
| 1408 | - | ||
| 1409 | -/** | ||
| 1410 | -* write the h264 sps/pps in context over RTMP. | ||
| 1411 | -*/ | ||
| 1412 | -int __srs_write_h264_sps_pps(Context* context, u_int32_t dts, u_int32_t pts) | ||
| 1413 | -{ | ||
| 1414 | - int ret = ERROR_SUCCESS; | ||
| 1415 | - | ||
| 1416 | - // only send when both sps and pps changed. | ||
| 1417 | - if (!context->h264_sps_changed || !context->h264_pps_changed) { | ||
| 1418 | - return ret; | ||
| 1419 | - } | ||
| 1420 | - | ||
| 1421 | - // 5bytes sps/pps header: | ||
| 1422 | - // configurationVersion, AVCProfileIndication, profile_compatibility, | ||
| 1423 | - // AVCLevelIndication, lengthSizeMinusOne | ||
| 1424 | - // 3bytes size of sps: | ||
| 1425 | - // numOfSequenceParameterSets, sequenceParameterSetLength(2B) | ||
| 1426 | - // Nbytes of sps. | ||
| 1427 | - // sequenceParameterSetNALUnit | ||
| 1428 | - // 3bytes size of pps: | ||
| 1429 | - // numOfPictureParameterSets, pictureParameterSetLength | ||
| 1430 | - // Nbytes of pps: | ||
| 1431 | - // pictureParameterSetNALUnit | ||
| 1432 | - int nb_packet = 5 | ||
| 1433 | - + 3 + (int)context->h264_sps.length() | ||
| 1434 | - + 3 + (int)context->h264_pps.length(); | ||
| 1435 | - char* packet = new char[nb_packet]; | ||
| 1436 | - SrsAutoFree(char, packet); | ||
| 1437 | - | ||
| 1438 | - // use stream to generate the h264 packet. | ||
| 1439 | - SrsStream stream; | ||
| 1440 | - if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 1441 | - return ret; | ||
| 1442 | - } | ||
| 1443 | - | ||
| 1444 | - // decode the SPS: | ||
| 1445 | - // @see: 7.3.2.1.1, H.264-AVC-ISO_IEC_14496-10-2012.pdf, page 62 | ||
| 1446 | - if (true) { | ||
| 1447 | - srs_assert((int)context->h264_sps.length() >= 4); | ||
| 1448 | - char* frame = (char*)context->h264_sps.data(); | ||
| 1449 | - | ||
| 1450 | - // @see: Annex A Profiles and levels, H.264-AVC-ISO_IEC_14496-10.pdf, page 205 | ||
| 1451 | - // Baseline profile profile_idc is 66(0x42). | ||
| 1452 | - // Main profile profile_idc is 77(0x4d). | ||
| 1453 | - // Extended profile profile_idc is 88(0x58). | ||
| 1454 | - u_int8_t profile_idc = frame[1]; | ||
| 1455 | - //u_int8_t constraint_set = frame[2]; | ||
| 1456 | - u_int8_t level_idc = frame[3]; | ||
| 1457 | - | ||
| 1458 | - // generate the sps/pps header | ||
| 1459 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1460 | - // configurationVersion | ||
| 1461 | - stream.write_1bytes(0x01); | ||
| 1462 | - // AVCProfileIndication | ||
| 1463 | - stream.write_1bytes(profile_idc); | ||
| 1464 | - // profile_compatibility | ||
| 1465 | - stream.write_1bytes(0x00); | ||
| 1466 | - // AVCLevelIndication | ||
| 1467 | - stream.write_1bytes(level_idc); | ||
| 1468 | - // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size, | ||
| 1469 | - // so we always set it to 0x03. | ||
| 1470 | - stream.write_1bytes(0x03); | ||
| 1471 | - } | ||
| 1472 | - | ||
| 1473 | - // sps | ||
| 1474 | - if (true) { | ||
| 1475 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1476 | - // numOfSequenceParameterSets, always 1 | ||
| 1477 | - stream.write_1bytes(0x01); | ||
| 1478 | - // sequenceParameterSetLength | ||
| 1479 | - stream.write_2bytes(context->h264_sps.length()); | ||
| 1480 | - // sequenceParameterSetNALUnit | ||
| 1481 | - stream.write_string(context->h264_sps); | ||
| 1482 | - } | ||
| 1483 | - | ||
| 1484 | - // pps | ||
| 1485 | - if (true) { | ||
| 1486 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1487 | - // numOfPictureParameterSets, always 1 | ||
| 1488 | - stream.write_1bytes(0x01); | ||
| 1489 | - // pictureParameterSetLength | ||
| 1490 | - stream.write_2bytes(context->h264_pps.length()); | ||
| 1491 | - // pictureParameterSetNALUnit | ||
| 1492 | - stream.write_string(context->h264_pps); | ||
| 1493 | - } | ||
| 1494 | - | ||
| 1495 | - // reset sps and pps. | ||
| 1496 | - context->h264_sps_changed = false; | ||
| 1497 | - context->h264_pps_changed = false; | ||
| 1498 | - context->h264_sps_pps_sent = true; | ||
| 1499 | - | ||
| 1500 | - // TODO: FIXME: for more profile. | ||
| 1501 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1502 | - // profile_idc == 100 || profile_idc == 110 || profile_idc == 122 || profile_idc == 144 | ||
| 1503 | - | ||
| 1504 | - // send out h264 packet. | ||
| 1505 | - int8_t frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1506 | - int8_t avc_packet_type = SrsCodecVideoAVCTypeSequenceHeader; | ||
| 1507 | - return __srs_write_h264_packet( | ||
| 1508 | - context, frame_type, avc_packet_type, | ||
| 1509 | - packet, nb_packet, dts, pts | ||
| 1510 | - ); | ||
| 1511 | -} | ||
| 1512 | - | ||
| 1513 | -/** | ||
| 1514 | -* write h264 IPB-frame. | ||
| 1515 | -*/ | ||
| 1516 | -int __srs_write_h264_ipb_frame(Context* context, | ||
| 1517 | - char* data, int size, u_int32_t dts, u_int32_t pts | ||
| 1518 | -) { | ||
| 1519 | - int ret = ERROR_SUCCESS; | ||
| 1520 | - | ||
| 1521 | - // when sps or pps not sent, ignore the packet. | ||
| 1522 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1523 | - if (!context->h264_sps_pps_sent) { | ||
| 1524 | - return ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
| 1525 | - } | ||
| 1526 | - | ||
| 1527 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 1528 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1529 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1530 | - u_int8_t nal_unit_type = (char)data[0] & 0x1f; | ||
| 1531 | - | ||
| 1532 | - // 4bytes size of nalu: | ||
| 1533 | - // NALUnitLength | ||
| 1534 | - // Nbytes of nalu. | ||
| 1535 | - // NALUnit | ||
| 1536 | - int nb_packet = 4 + size; | ||
| 1537 | - char* packet = new char[nb_packet]; | ||
| 1538 | - SrsAutoFree(char, packet); | ||
| 1539 | - | ||
| 1540 | - // use stream to generate the h264 packet. | ||
| 1541 | - SrsStream stream; | ||
| 1542 | - if ((ret = stream.initialize(packet, nb_packet)) != ERROR_SUCCESS) { | ||
| 1543 | - return ret; | ||
| 1544 | - } | ||
| 1545 | - | ||
| 1546 | - // 5.3.4.2.1 Syntax, H.264-AVC-ISO_IEC_14496-15.pdf, page 16 | ||
| 1547 | - // lengthSizeMinusOne, or NAL_unit_length, always use 4bytes size | ||
| 1548 | - u_int32_t NAL_unit_length = size; | ||
| 1549 | - | ||
| 1550 | - // mux the avc NALU in "ISO Base Media File Format" | ||
| 1551 | - // from H.264-AVC-ISO_IEC_14496-15.pdf, page 20 | ||
| 1552 | - // NALUnitLength | ||
| 1553 | - stream.write_4bytes(NAL_unit_length); | ||
| 1554 | - // NALUnit | ||
| 1555 | - stream.write_bytes(data, size); | ||
| 1556 | - | ||
| 1557 | - // send out h264 packet. | ||
| 1558 | - int8_t frame_type = SrsCodecVideoAVCFrameInterFrame; | ||
| 1559 | - if (nal_unit_type != 1) { | ||
| 1560 | - frame_type = SrsCodecVideoAVCFrameKeyFrame; | ||
| 1561 | - } | ||
| 1562 | - int8_t avc_packet_type = SrsCodecVideoAVCTypeNALU; | ||
| 1563 | - return __srs_write_h264_packet( | ||
| 1564 | - context, frame_type, avc_packet_type, | ||
| 1565 | - packet, nb_packet, dts, pts | ||
| 1566 | - ); | ||
| 1567 | - | ||
| 1568 | - return ret; | ||
| 1569 | -} | ||
| 1570 | - | ||
| 1571 | -/** | ||
| 1572 | -* write h264 raw frame, maybe sps/pps/IPB-frame. | ||
| 1573 | -*/ | ||
| 1574 | -int __srs_write_h264_raw_frame(Context* context, | ||
| 1575 | - char* frame, int frame_size, u_int32_t dts, u_int32_t pts | ||
| 1576 | -) { | ||
| 1577 | - int ret = ERROR_SUCCESS; | ||
| 1578 | - | ||
| 1579 | - // ignore invalid frame, | ||
| 1580 | - // atleast 1bytes for SPS to decode the type | ||
| 1581 | - if (frame_size < 1) { | ||
| 1582 | - return ret; | ||
| 1583 | - } | ||
| 1584 | - | ||
| 1585 | - // 5bits, 7.3.1 NAL unit syntax, | ||
| 1586 | - // H.264-AVC-ISO_IEC_14496-10.pdf, page 44. | ||
| 1587 | - // 7: SPS, 8: PPS, 5: I Frame, 1: P Frame | ||
| 1588 | - u_int8_t nal_unit_type = (char)frame[0] & 0x1f; | ||
| 1589 | - | ||
| 1590 | - if (nal_unit_type == 7) { | ||
| 1591 | - // atleast 1bytes for SPS to decode the type, profile, constrain and level. | ||
| 1592 | - if (frame_size < 4) { | ||
| 1593 | - return ret; | ||
| 1594 | - } | ||
| 1595 | - | ||
| 1596 | - std::string sps; | ||
| 1597 | - sps.append(frame, frame_size); | ||
| 1598 | - | ||
| 1599 | - if (context->h264_sps == sps) { | ||
| 1600 | - return ERROR_H264_DUPLICATED_SPS; | ||
| 1601 | - } | ||
| 1602 | - context->h264_sps_changed = true; | ||
| 1603 | - context->h264_sps = sps; | ||
| 1604 | - | ||
| 1605 | - return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1606 | - } else if (nal_unit_type == 8) { | ||
| 1607 | - | ||
| 1608 | - std::string pps; | ||
| 1609 | - pps.append(frame, frame_size); | ||
| 1610 | - | ||
| 1611 | - if (context->h264_pps == pps) { | ||
| 1612 | - return ERROR_H264_DUPLICATED_PPS; | ||
| 1613 | - } | ||
| 1614 | - context->h264_pps_changed = true; | ||
| 1615 | - context->h264_pps = pps; | ||
| 1616 | - | ||
| 1617 | - return __srs_write_h264_sps_pps(context, dts, pts); | ||
| 1618 | - } else { | ||
| 1619 | - return __srs_write_h264_ipb_frame(context, frame, frame_size, dts, pts); | ||
| 1620 | - } | ||
| 1621 | - | ||
| 1622 | - return ret; | ||
| 1623 | -} | ||
| 1624 | - | ||
| 1625 | -/** | ||
| 1626 | -* write h264 multiple frames, in annexb format. | ||
| 1627 | -*/ | ||
| 1628 | -int srs_h264_write_raw_frames(srs_rtmp_t rtmp, | ||
| 1629 | - char* frames, int frames_size, u_int32_t dts, u_int32_t pts | ||
| 1630 | -) { | ||
| 1631 | - int ret = ERROR_SUCCESS; | ||
| 1632 | - | ||
| 1633 | - srs_assert(frames != NULL); | ||
| 1634 | - srs_assert(frames_size > 0); | ||
| 1635 | - | ||
| 1636 | - srs_assert(rtmp != NULL); | ||
| 1637 | - Context* context = (Context*)rtmp; | ||
| 1638 | - | ||
| 1639 | - if ((ret = context->h264_raw_stream.initialize(frames, frames_size)) != ERROR_SUCCESS) { | ||
| 1640 | - return ret; | ||
| 1641 | - } | ||
| 1642 | - | ||
| 1643 | - // use the last error | ||
| 1644 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/203 | ||
| 1645 | - // @see https://github.com/winlinvip/simple-rtmp-server/issues/204 | ||
| 1646 | - int error_code_return = ret; | ||
| 1647 | - | ||
| 1648 | - // send each frame. | ||
| 1649 | - while (!context->h264_raw_stream.empty()) { | ||
| 1650 | - // each frame must prefixed by annexb format. | ||
| 1651 | - // about annexb, @see H.264-AVC-ISO_IEC_14496-10.pdf, page 211. | ||
| 1652 | - int pnb_start_code = 0; | ||
| 1653 | - if (!srs_avc_startswith_annexb(&context->h264_raw_stream, &pnb_start_code)) { | ||
| 1654 | - return ERROR_H264_API_NO_PREFIXED; | ||
| 1655 | - } | ||
| 1656 | - int start = context->h264_raw_stream.pos() + pnb_start_code; | ||
| 1657 | - | ||
| 1658 | - // find the last frame prefixed by annexb format. | ||
| 1659 | - context->h264_raw_stream.skip(pnb_start_code); | ||
| 1660 | - while (!context->h264_raw_stream.empty()) { | ||
| 1661 | - if (srs_avc_startswith_annexb(&context->h264_raw_stream, NULL)) { | ||
| 1662 | - break; | ||
| 1663 | - } | ||
| 1664 | - context->h264_raw_stream.skip(1); | ||
| 1665 | - } | ||
| 1666 | - int size = context->h264_raw_stream.pos() - start; | ||
| 1667 | - | ||
| 1668 | - // send out the frame. | ||
| 1669 | - char* frame = context->h264_raw_stream.data() + start; | ||
| 1670 | - | ||
| 1671 | - // it may be return error, but we must process all packets. | ||
| 1672 | - if ((ret = __srs_write_h264_raw_frame(context, frame, size, dts, pts)) != ERROR_SUCCESS) { | ||
| 1673 | - error_code_return = ret; | ||
| 1674 | - | ||
| 1675 | - // ignore known error, process all packets. | ||
| 1676 | - if (srs_h264_is_dvbsp_error(ret) | ||
| 1677 | - || srs_h264_is_duplicated_sps_error(ret) | ||
| 1678 | - || srs_h264_is_duplicated_pps_error(ret) | ||
| 1679 | - ) { | ||
| 1680 | - continue; | ||
| 1681 | - } | ||
| 1682 | - | ||
| 1683 | - return ret; | ||
| 1684 | - } | ||
| 1685 | - } | ||
| 1686 | - | ||
| 1687 | - return error_code_return; | ||
| 1688 | -} | ||
| 1689 | - | ||
| 1690 | -srs_h264_bool srs_h264_is_dvbsp_error(int error_code) | ||
| 1691 | -{ | ||
| 1692 | - return error_code == ERROR_H264_DROP_BEFORE_SPS_PPS; | ||
| 1693 | -} | ||
| 1694 | - | ||
| 1695 | -srs_h264_bool srs_h264_is_duplicated_sps_error(int error_code) | ||
| 1696 | -{ | ||
| 1697 | - return error_code == ERROR_H264_DUPLICATED_SPS; | ||
| 1698 | -} | ||
| 1699 | - | ||
| 1700 | -srs_h264_bool srs_h264_is_duplicated_pps_error(int error_code) | ||
| 1701 | -{ | ||
| 1702 | - return error_code == ERROR_H264_DUPLICATED_PPS; | ||
| 1703 | -} | ||
| 1704 | - | ||
| 1705 | -int srs_h264_startswith_annexb(char* h264_raw_data, int h264_raw_size, int* pnb_start_code) | ||
| 1706 | -{ | ||
| 1707 | - SrsStream stream; | ||
| 1708 | - if (stream.initialize(h264_raw_data, h264_raw_size) != ERROR_SUCCESS) { | ||
| 1709 | - return false; | ||
| 1710 | - } | ||
| 1711 | - | ||
| 1712 | - return srs_avc_startswith_annexb(&stream, pnb_start_code); | ||
| 1713 | -} | ||
| 1714 | - | ||
| 1715 | int64_t srs_utils_get_time_ms() | 1715 | int64_t srs_utils_get_time_ms() |
| 1716 | { | 1716 | { |
| 1717 | srs_update_system_time_ms(); | 1717 | srs_update_system_time_ms(); |
| @@ -264,164 +264,6 @@ extern int srs_rtmp_write_packet(srs_rtmp_t rtmp, | @@ -264,164 +264,6 @@ extern int srs_rtmp_write_packet(srs_rtmp_t rtmp, | ||
| 264 | 264 | ||
| 265 | /************************************************************* | 265 | /************************************************************* |
| 266 | ************************************************************** | 266 | ************************************************************** |
| 267 | -* flv codec | ||
| 268 | -* @example /trunk/research/librtmp/srs_flv_injecter.c | ||
| 269 | -* @example /trunk/research/librtmp/srs_flv_parser.c | ||
| 270 | -* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 271 | -* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 272 | -************************************************************** | ||
| 273 | -*************************************************************/ | ||
| 274 | -typedef void* srs_flv_t; | ||
| 275 | -typedef int srs_flv_bool; | ||
| 276 | -/* open flv file for both read/write. */ | ||
| 277 | -extern srs_flv_t srs_flv_open_read(const char* file); | ||
| 278 | -extern srs_flv_t srs_flv_open_write(const char* file); | ||
| 279 | -extern void srs_flv_close(srs_flv_t flv); | ||
| 280 | -/** | ||
| 281 | -* read the flv header. 9bytes header. | ||
| 282 | -* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 283 | -* 3bytes, signature, "FLV", | ||
| 284 | -* 1bytes, version, 0x01, | ||
| 285 | -* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 286 | -* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 287 | -* | ||
| 288 | -* @return 0, success; otherswise, failed. | ||
| 289 | -* @remark, drop the 4bytes zero previous tag size. | ||
| 290 | -*/ | ||
| 291 | -extern int srs_flv_read_header(srs_flv_t flv, char header[9]); | ||
| 292 | -/** | ||
| 293 | -* read the flv tag header, 1bytes tag, 3bytes data_size, | ||
| 294 | -* 4bytes time, 3bytes stream id. | ||
| 295 | -* @param ptype, output the type of tag, macros: | ||
| 296 | -* SRS_RTMP_TYPE_AUDIO, FlvTagAudio | ||
| 297 | -* SRS_RTMP_TYPE_VIDEO, FlvTagVideo | ||
| 298 | -* SRS_RTMP_TYPE_SCRIPT, FlvTagScript | ||
| 299 | -* @param pdata_size, output the size of tag data. | ||
| 300 | -* @param ptime, output the time of tag, the dts in ms. | ||
| 301 | -* | ||
| 302 | -* @return 0, success; otherswise, failed. | ||
| 303 | -* @remark, user must ensure the next is a tag, srs never check it. | ||
| 304 | -*/ | ||
| 305 | -extern int srs_flv_read_tag_header(srs_flv_t flv, | ||
| 306 | - char* ptype, int32_t* pdata_size, u_int32_t* ptime | ||
| 307 | -); | ||
| 308 | -/** | ||
| 309 | -* read the tag data. drop the 4bytes previous tag size | ||
| 310 | -* @param data, the data to read, user alloc and free it. | ||
| 311 | -* @param size, the size of data to read, get by srs_flv_read_tag_header(). | ||
| 312 | -* @remark, srs will ignore and drop the 4bytes previous tag size. | ||
| 313 | -*/ | ||
| 314 | -extern int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); | ||
| 315 | -/** | ||
| 316 | -* write the flv header. 9bytes header. | ||
| 317 | -* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 318 | -* 3bytes, signature, "FLV", | ||
| 319 | -* 1bytes, version, 0x01, | ||
| 320 | -* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 321 | -* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 322 | -* | ||
| 323 | -* @return 0, success; otherswise, failed. | ||
| 324 | -* @remark, auto write the 4bytes zero previous tag size. | ||
| 325 | -*/ | ||
| 326 | -extern int srs_flv_write_header(srs_flv_t flv, char header[9]); | ||
| 327 | -/** | ||
| 328 | -* write the flv tag to file. | ||
| 329 | -* | ||
| 330 | -* @return 0, success; otherswise, failed. | ||
| 331 | -* @remark, auto write the 4bytes zero previous tag size. | ||
| 332 | -*/ | ||
| 333 | -/* write flv tag to file, auto write the 4bytes previous tag size */ | ||
| 334 | -extern int srs_flv_write_tag(srs_flv_t flv, | ||
| 335 | - char type, int32_t time, char* data, int size | ||
| 336 | -); | ||
| 337 | -/** | ||
| 338 | -* get the tag size, for flv injecter to adjust offset, | ||
| 339 | -* size = tag_header(11B) + data_size + previous_tag(4B) | ||
| 340 | -* @return the size of tag. | ||
| 341 | -*/ | ||
| 342 | -extern int srs_flv_size_tag(int data_size); | ||
| 343 | -/* file stream */ | ||
| 344 | -/* file stream tellg to get offset */ | ||
| 345 | -extern int64_t srs_flv_tellg(srs_flv_t flv); | ||
| 346 | -/* seek file stream, offset is form the start of file */ | ||
| 347 | -extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); | ||
| 348 | -/* error code */ | ||
| 349 | -/* whether the error code indicates EOF */ | ||
| 350 | -extern srs_flv_bool srs_flv_is_eof(int error_code); | ||
| 351 | -/* media codec */ | ||
| 352 | -/** | ||
| 353 | -* whether the video body is sequence header | ||
| 354 | -* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 355 | -* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 356 | -*/ | ||
| 357 | -extern srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size); | ||
| 358 | -/** | ||
| 359 | -* whether the video body is keyframe | ||
| 360 | -* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 361 | -* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 362 | -*/ | ||
| 363 | -extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size); | ||
| 364 | - | ||
| 365 | -/************************************************************* | ||
| 366 | -************************************************************** | ||
| 367 | -* amf0 codec | ||
| 368 | -* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 369 | -* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 370 | -************************************************************** | ||
| 371 | -*************************************************************/ | ||
| 372 | -/* the output handler. */ | ||
| 373 | -typedef void* srs_amf0_t; | ||
| 374 | -typedef int srs_amf0_bool; | ||
| 375 | -typedef double srs_amf0_number; | ||
| 376 | -/** | ||
| 377 | -* parse amf0 from data. | ||
| 378 | -* @param nparsed, the parsed size, NULL to ignore. | ||
| 379 | -* @return the parsed amf0 object. NULL for error. | ||
| 380 | -*/ | ||
| 381 | -extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | ||
| 382 | -extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); | ||
| 383 | -extern srs_amf0_t srs_amf0_create_ecma_array(); | ||
| 384 | -extern srs_amf0_t srs_amf0_create_strict_array(); | ||
| 385 | -extern srs_amf0_t srs_amf0_create_object(); | ||
| 386 | -extern void srs_amf0_free(srs_amf0_t amf0); | ||
| 387 | -extern void srs_amf0_free_bytes(char* data); | ||
| 388 | -/* size and to bytes */ | ||
| 389 | -extern int srs_amf0_size(srs_amf0_t amf0); | ||
| 390 | -extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); | ||
| 391 | -/* type detecter */ | ||
| 392 | -extern srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0); | ||
| 393 | -extern srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); | ||
| 394 | -extern srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0); | ||
| 395 | -extern srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0); | ||
| 396 | -extern srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0); | ||
| 397 | -extern srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); | ||
| 398 | -extern srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0); | ||
| 399 | -/* value converter */ | ||
| 400 | -extern const char* srs_amf0_to_string(srs_amf0_t amf0); | ||
| 401 | -extern srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0); | ||
| 402 | -extern srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0); | ||
| 403 | -/* value setter */ | ||
| 404 | -extern void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value); | ||
| 405 | -/* object value converter */ | ||
| 406 | -extern int srs_amf0_object_property_count(srs_amf0_t amf0); | ||
| 407 | -extern const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | ||
| 408 | -extern srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); | ||
| 409 | -extern srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); | ||
| 410 | -extern void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 411 | -extern void srs_amf0_object_clear(srs_amf0_t amf0); | ||
| 412 | -/* ecma array value converter */ | ||
| 413 | -extern int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); | ||
| 414 | -extern const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); | ||
| 415 | -extern srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); | ||
| 416 | -extern srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); | ||
| 417 | -extern void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 418 | -/* strict array value converter */ | ||
| 419 | -extern int srs_amf0_strict_array_property_count(srs_amf0_t amf0); | ||
| 420 | -extern srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); | ||
| 421 | -extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); | ||
| 422 | - | ||
| 423 | -/************************************************************* | ||
| 424 | -************************************************************** | ||
| 425 | * audio raw codec | 267 | * audio raw codec |
| 426 | ************************************************************** | 268 | ************************************************************** |
| 427 | *************************************************************/ | 269 | *************************************************************/ |
| @@ -585,6 +427,164 @@ extern int srs_h264_startswith_annexb( | @@ -585,6 +427,164 @@ extern int srs_h264_startswith_annexb( | ||
| 585 | 427 | ||
| 586 | /************************************************************* | 428 | /************************************************************* |
| 587 | ************************************************************** | 429 | ************************************************************** |
| 430 | +* flv codec | ||
| 431 | +* @example /trunk/research/librtmp/srs_flv_injecter.c | ||
| 432 | +* @example /trunk/research/librtmp/srs_flv_parser.c | ||
| 433 | +* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 434 | +* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 435 | +************************************************************** | ||
| 436 | +*************************************************************/ | ||
| 437 | +typedef void* srs_flv_t; | ||
| 438 | +typedef int srs_flv_bool; | ||
| 439 | +/* open flv file for both read/write. */ | ||
| 440 | +extern srs_flv_t srs_flv_open_read(const char* file); | ||
| 441 | +extern srs_flv_t srs_flv_open_write(const char* file); | ||
| 442 | +extern void srs_flv_close(srs_flv_t flv); | ||
| 443 | +/** | ||
| 444 | +* read the flv header. 9bytes header. | ||
| 445 | +* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 446 | +* 3bytes, signature, "FLV", | ||
| 447 | +* 1bytes, version, 0x01, | ||
| 448 | +* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 449 | +* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 450 | +* | ||
| 451 | +* @return 0, success; otherswise, failed. | ||
| 452 | +* @remark, drop the 4bytes zero previous tag size. | ||
| 453 | +*/ | ||
| 454 | +extern int srs_flv_read_header(srs_flv_t flv, char header[9]); | ||
| 455 | +/** | ||
| 456 | +* read the flv tag header, 1bytes tag, 3bytes data_size, | ||
| 457 | +* 4bytes time, 3bytes stream id. | ||
| 458 | +* @param ptype, output the type of tag, macros: | ||
| 459 | +* SRS_RTMP_TYPE_AUDIO, FlvTagAudio | ||
| 460 | +* SRS_RTMP_TYPE_VIDEO, FlvTagVideo | ||
| 461 | +* SRS_RTMP_TYPE_SCRIPT, FlvTagScript | ||
| 462 | +* @param pdata_size, output the size of tag data. | ||
| 463 | +* @param ptime, output the time of tag, the dts in ms. | ||
| 464 | +* | ||
| 465 | +* @return 0, success; otherswise, failed. | ||
| 466 | +* @remark, user must ensure the next is a tag, srs never check it. | ||
| 467 | +*/ | ||
| 468 | +extern int srs_flv_read_tag_header(srs_flv_t flv, | ||
| 469 | + char* ptype, int32_t* pdata_size, u_int32_t* ptime | ||
| 470 | +); | ||
| 471 | +/** | ||
| 472 | +* read the tag data. drop the 4bytes previous tag size | ||
| 473 | +* @param data, the data to read, user alloc and free it. | ||
| 474 | +* @param size, the size of data to read, get by srs_flv_read_tag_header(). | ||
| 475 | +* @remark, srs will ignore and drop the 4bytes previous tag size. | ||
| 476 | +*/ | ||
| 477 | +extern int srs_flv_read_tag_data(srs_flv_t flv, char* data, int32_t size); | ||
| 478 | +/** | ||
| 479 | +* write the flv header. 9bytes header. | ||
| 480 | +* @param header, @see E.2 The FLV header, flv_v10_1.pdf in SRS doc. | ||
| 481 | +* 3bytes, signature, "FLV", | ||
| 482 | +* 1bytes, version, 0x01, | ||
| 483 | +* 1bytes, flags, UB[5] 0, UB[1] audio present, UB[1] 0, UB[1] video present. | ||
| 484 | +* 4bytes, dataoffset, 0x09, The length of this header in bytes | ||
| 485 | +* | ||
| 486 | +* @return 0, success; otherswise, failed. | ||
| 487 | +* @remark, auto write the 4bytes zero previous tag size. | ||
| 488 | +*/ | ||
| 489 | +extern int srs_flv_write_header(srs_flv_t flv, char header[9]); | ||
| 490 | +/** | ||
| 491 | +* write the flv tag to file. | ||
| 492 | +* | ||
| 493 | +* @return 0, success; otherswise, failed. | ||
| 494 | +* @remark, auto write the 4bytes zero previous tag size. | ||
| 495 | +*/ | ||
| 496 | +/* write flv tag to file, auto write the 4bytes previous tag size */ | ||
| 497 | +extern int srs_flv_write_tag(srs_flv_t flv, | ||
| 498 | + char type, int32_t time, char* data, int size | ||
| 499 | +); | ||
| 500 | +/** | ||
| 501 | +* get the tag size, for flv injecter to adjust offset, | ||
| 502 | +* size = tag_header(11B) + data_size + previous_tag(4B) | ||
| 503 | +* @return the size of tag. | ||
| 504 | +*/ | ||
| 505 | +extern int srs_flv_size_tag(int data_size); | ||
| 506 | +/* file stream */ | ||
| 507 | +/* file stream tellg to get offset */ | ||
| 508 | +extern int64_t srs_flv_tellg(srs_flv_t flv); | ||
| 509 | +/* seek file stream, offset is form the start of file */ | ||
| 510 | +extern void srs_flv_lseek(srs_flv_t flv, int64_t offset); | ||
| 511 | +/* error code */ | ||
| 512 | +/* whether the error code indicates EOF */ | ||
| 513 | +extern srs_flv_bool srs_flv_is_eof(int error_code); | ||
| 514 | +/* media codec */ | ||
| 515 | +/** | ||
| 516 | +* whether the video body is sequence header | ||
| 517 | +* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 518 | +* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 519 | +*/ | ||
| 520 | +extern srs_flv_bool srs_flv_is_sequence_header(char* data, int32_t size); | ||
| 521 | +/** | ||
| 522 | +* whether the video body is keyframe | ||
| 523 | +* @param data, the data of tag, read by srs_flv_read_tag_data(). | ||
| 524 | +* @param size, the size of tag, read by srs_flv_read_tag_data(). | ||
| 525 | +*/ | ||
| 526 | +extern srs_flv_bool srs_flv_is_keyframe(char* data, int32_t size); | ||
| 527 | + | ||
| 528 | +/************************************************************* | ||
| 529 | +************************************************************** | ||
| 530 | +* amf0 codec | ||
| 531 | +* @example /trunk/research/librtmp/srs_ingest_flv.c | ||
| 532 | +* @example /trunk/research/librtmp/srs_ingest_rtmp.c | ||
| 533 | +************************************************************** | ||
| 534 | +*************************************************************/ | ||
| 535 | +/* the output handler. */ | ||
| 536 | +typedef void* srs_amf0_t; | ||
| 537 | +typedef int srs_amf0_bool; | ||
| 538 | +typedef double srs_amf0_number; | ||
| 539 | +/** | ||
| 540 | +* parse amf0 from data. | ||
| 541 | +* @param nparsed, the parsed size, NULL to ignore. | ||
| 542 | +* @return the parsed amf0 object. NULL for error. | ||
| 543 | +*/ | ||
| 544 | +extern srs_amf0_t srs_amf0_parse(char* data, int size, int* nparsed); | ||
| 545 | +extern srs_amf0_t srs_amf0_create_number(srs_amf0_number value); | ||
| 546 | +extern srs_amf0_t srs_amf0_create_ecma_array(); | ||
| 547 | +extern srs_amf0_t srs_amf0_create_strict_array(); | ||
| 548 | +extern srs_amf0_t srs_amf0_create_object(); | ||
| 549 | +extern void srs_amf0_free(srs_amf0_t amf0); | ||
| 550 | +extern void srs_amf0_free_bytes(char* data); | ||
| 551 | +/* size and to bytes */ | ||
| 552 | +extern int srs_amf0_size(srs_amf0_t amf0); | ||
| 553 | +extern int srs_amf0_serialize(srs_amf0_t amf0, char* data, int size); | ||
| 554 | +/* type detecter */ | ||
| 555 | +extern srs_amf0_bool srs_amf0_is_string(srs_amf0_t amf0); | ||
| 556 | +extern srs_amf0_bool srs_amf0_is_boolean(srs_amf0_t amf0); | ||
| 557 | +extern srs_amf0_bool srs_amf0_is_number(srs_amf0_t amf0); | ||
| 558 | +extern srs_amf0_bool srs_amf0_is_null(srs_amf0_t amf0); | ||
| 559 | +extern srs_amf0_bool srs_amf0_is_object(srs_amf0_t amf0); | ||
| 560 | +extern srs_amf0_bool srs_amf0_is_ecma_array(srs_amf0_t amf0); | ||
| 561 | +extern srs_amf0_bool srs_amf0_is_strict_array(srs_amf0_t amf0); | ||
| 562 | +/* value converter */ | ||
| 563 | +extern const char* srs_amf0_to_string(srs_amf0_t amf0); | ||
| 564 | +extern srs_amf0_bool srs_amf0_to_boolean(srs_amf0_t amf0); | ||
| 565 | +extern srs_amf0_number srs_amf0_to_number(srs_amf0_t amf0); | ||
| 566 | +/* value setter */ | ||
| 567 | +extern void srs_amf0_set_number(srs_amf0_t amf0, srs_amf0_number value); | ||
| 568 | +/* object value converter */ | ||
| 569 | +extern int srs_amf0_object_property_count(srs_amf0_t amf0); | ||
| 570 | +extern const char* srs_amf0_object_property_name_at(srs_amf0_t amf0, int index); | ||
| 571 | +extern srs_amf0_t srs_amf0_object_property_value_at(srs_amf0_t amf0, int index); | ||
| 572 | +extern srs_amf0_t srs_amf0_object_property(srs_amf0_t amf0, const char* name); | ||
| 573 | +extern void srs_amf0_object_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 574 | +extern void srs_amf0_object_clear(srs_amf0_t amf0); | ||
| 575 | +/* ecma array value converter */ | ||
| 576 | +extern int srs_amf0_ecma_array_property_count(srs_amf0_t amf0); | ||
| 577 | +extern const char* srs_amf0_ecma_array_property_name_at(srs_amf0_t amf0, int index); | ||
| 578 | +extern srs_amf0_t srs_amf0_ecma_array_property_value_at(srs_amf0_t amf0, int index); | ||
| 579 | +extern srs_amf0_t srs_amf0_ecma_array_property(srs_amf0_t amf0, const char* name); | ||
| 580 | +extern void srs_amf0_ecma_array_property_set(srs_amf0_t amf0, const char* name, srs_amf0_t value); | ||
| 581 | +/* strict array value converter */ | ||
| 582 | +extern int srs_amf0_strict_array_property_count(srs_amf0_t amf0); | ||
| 583 | +extern srs_amf0_t srs_amf0_strict_array_property_at(srs_amf0_t amf0, int index); | ||
| 584 | +extern void srs_amf0_strict_array_append(srs_amf0_t amf0, srs_amf0_t value); | ||
| 585 | + | ||
| 586 | +/************************************************************* | ||
| 587 | +************************************************************** | ||
| 588 | * utilities | 588 | * utilities |
| 589 | ************************************************************** | 589 | ************************************************************** |
| 590 | *************************************************************/ | 590 | *************************************************************/ |
-
请 注册 或 登录 后发表评论