正在显示
2 个修改的文件
包含
638 行增加
和
341 行删除
| @@ -21,6 +21,11 @@ enum media_type{ | @@ -21,6 +21,11 @@ enum media_type{ | ||
| 21 | mt_av = 3, | 21 | mt_av = 3, |
| 22 | }; | 22 | }; |
| 23 | 23 | ||
| 24 | +enum media_role { | ||
| 25 | + mr_teacher =0, | ||
| 26 | + mr_student =1, | ||
| 27 | +}; | ||
| 28 | + | ||
| 24 | enum timestamp_type{ | 29 | enum timestamp_type{ |
| 25 | tt_start = 0, | 30 | tt_start = 0, |
| 26 | tt_end = 1, | 31 | tt_end = 1, |
| @@ -33,7 +38,7 @@ public: | @@ -33,7 +38,7 @@ public: | ||
| 33 | string name; | 38 | string name; |
| 34 | int index; | 39 | int index; |
| 35 | media_type m_type; | 40 | media_type m_type; |
| 36 | - int channel; | 41 | + media_role m_rote; |
| 37 | int rotate; //degree,0,90,180 ... | 42 | int rotate; //degree,0,90,180 ... |
| 38 | }; | 43 | }; |
| 39 | 44 | ||
| @@ -47,8 +52,8 @@ public: | @@ -47,8 +52,8 @@ public: | ||
| 47 | 52 | ||
| 48 | float duration; | 53 | float duration; |
| 49 | int index; | 54 | int index; |
| 50 | - int channel; | ||
| 51 | media_type m_type; | 55 | media_type m_type; |
| 56 | + media_role m_rote; | ||
| 52 | timestamp_type t_type; | 57 | timestamp_type t_type; |
| 53 | }; | 58 | }; |
| 54 | 59 | ||
| @@ -120,40 +125,24 @@ char acodec_param[1024]; | @@ -120,40 +125,24 @@ char acodec_param[1024]; | ||
| 120 | char pip_param[1024]; | 125 | char pip_param[1024]; |
| 121 | char pip1_param[1024]; | 126 | char pip1_param[1024]; |
| 122 | 127 | ||
| 123 | -bool first_time_set = false; | ||
| 124 | -float start_time = 0.0f; | ||
| 125 | - | ||
| 126 | -void init_read_file() { | ||
| 127 | - first_time_set = false; | ||
| 128 | - start_time = 0.0f; | ||
| 129 | -} | ||
| 130 | - | ||
| 131 | - | ||
| 132 | -void addinfo(string t, string name, bool bstart){ | 128 | +void addinfo(float t, string name, bool bstart,media_role role){ |
| 133 | media_type mtype = name.substr(name.length() - 4, name.length()) == ".aac" ? mt_audio : mt_video; | 129 | media_type mtype = name.substr(name.length() - 4, name.length()) == ".aac" ? mt_audio : mt_video; |
| 134 | if (bstart) { | 130 | if (bstart) { |
| 135 | fileinfo f; | 131 | fileinfo f; |
| 136 | - f.start_time = atof(t.c_str()); | 132 | + f.start_time = t; |
| 137 | f.end_time = f.start_time; | 133 | f.end_time = f.start_time; |
| 138 | f.name = name; | 134 | f.name = name; |
| 139 | f.m_type = mtype; | 135 | f.m_type = mtype; |
| 136 | + f.m_rote = role; | ||
| 140 | f.rotate = 0; | 137 | f.rotate = 0; |
| 141 | 138 | ||
| 142 | - if (!first_time_set) { | ||
| 143 | - first_time_set = true; | ||
| 144 | - start_time = f.start_time; | ||
| 145 | - } | ||
| 146 | - | ||
| 147 | - f.start_time -= start_time; | ||
| 148 | - | ||
| 149 | media_files.push_back(f); | 139 | media_files.push_back(f); |
| 150 | } | 140 | } |
| 151 | else { | 141 | else { |
| 152 | int i; | 142 | int i; |
| 153 | for (i = 0; i < media_files.size(); i++) { | 143 | for (i = 0; i < media_files.size(); i++) { |
| 154 | if (media_files[i].name == name) { | 144 | if (media_files[i].name == name) { |
| 155 | - media_files[i].end_time = atof(t.c_str()); | ||
| 156 | - media_files[i].end_time -= start_time; | 145 | + media_files[i].end_time = t; |
| 157 | break; | 146 | break; |
| 158 | } | 147 | } |
| 159 | } | 148 | } |
| @@ -187,7 +176,6 @@ void addinfo(float start, float duration, string name, int channel){ | @@ -187,7 +176,6 @@ void addinfo(float start, float duration, string name, int channel){ | ||
| 187 | f.end_time = f.start_time + duration; | 176 | f.end_time = f.start_time + duration; |
| 188 | f.name = name; | 177 | f.name = name; |
| 189 | f.m_type = mtype; | 178 | f.m_type = mtype; |
| 190 | - f.channel = channel; | ||
| 191 | 179 | ||
| 192 | media_files.push_back(f); | 180 | media_files.push_back(f); |
| 193 | } | 181 | } |
| @@ -680,7 +668,6 @@ void add_media_infos() | @@ -680,7 +668,6 @@ void add_media_infos() | ||
| 680 | m.end_time = f.end_time; | 668 | m.end_time = f.end_time; |
| 681 | m.m_type = f.m_type; | 669 | m.m_type = f.m_type; |
| 682 | m.t_type = tt_start; | 670 | m.t_type = tt_start; |
| 683 | - m.channel = f.channel; | ||
| 684 | m.duration = f.end_time - f.start_time; | 671 | m.duration = f.end_time - f.start_time; |
| 685 | m.type_time = m.start_time; | 672 | m.type_time = m.start_time; |
| 686 | m.rotate = f.rotate; | 673 | m.rotate = f.rotate; |
| @@ -847,54 +834,6 @@ int find_video_between_the_audio() | @@ -847,54 +834,6 @@ int find_video_between_the_audio() | ||
| 847 | return video_index; | 834 | return video_index; |
| 848 | } | 835 | } |
| 849 | 836 | ||
| 850 | -int merge_video_pip(vector<media_info> & files) | ||
| 851 | -{ | ||
| 852 | - char ch0_file[1024], ch1_file[1024]; | ||
| 853 | - vector<string> merge_video_files; | ||
| 854 | - | ||
| 855 | - media_info ch0_start, ch0_end, ch1_start, ch1_end; | ||
| 856 | - | ||
| 857 | - if (files[0].channel == 0) { | ||
| 858 | - ch0_start = files[0]; | ||
| 859 | - ch0_end = files[2]; | ||
| 860 | - ch1_start = files[1]; | ||
| 861 | - ch1_end = files[3]; | ||
| 862 | - } | ||
| 863 | - else { | ||
| 864 | - ch0_start = files[1]; | ||
| 865 | - ch0_end = files[3]; | ||
| 866 | - ch1_start = files[0]; | ||
| 867 | - ch1_end = files[2]; | ||
| 868 | - } | ||
| 869 | - | ||
| 870 | - | ||
| 871 | - if (ch0_start.type_time - ch0_start.start_time > 0.10 || ch0_end.end_time - ch0_end.type_time > 0.10) { | ||
| 872 | - sprintf(ch0_file, "%d_%s", nf, ch0_start.name.c_str()); | ||
| 873 | - split_av(ch0_start.name.c_str(), ch0_start.type_time - ch0_start.start_time, ch0_end.type_time - ch0_start.type_time, ch0_file); | ||
| 874 | - tmp_files.push_back(ch0_file); | ||
| 875 | - } | ||
| 876 | - else{ | ||
| 877 | - strcpy(ch0_file, ch0_start.name.c_str()); | ||
| 878 | - } | ||
| 879 | - | ||
| 880 | - | ||
| 881 | - if (ch1_start.type_time - ch1_start.start_time > 0.10 || ch1_end.end_time - ch1_end.type_time > 0.10) { | ||
| 882 | - sprintf(ch1_file, "%d_%s", nf, ch1_start.name.c_str()); | ||
| 883 | - split_av(ch1_start.name.c_str(), ch1_start.type_time - ch1_start.start_time, ch1_end.type_time - ch1_start.type_time, ch1_file); | ||
| 884 | - tmp_files.push_back(ch1_file); | ||
| 885 | - } | ||
| 886 | - else{ | ||
| 887 | - strcpy(ch1_file, ch1_start.name.c_str()); | ||
| 888 | - } | ||
| 889 | - | ||
| 890 | - sprintf(destfile, "%d.ts", nf); | ||
| 891 | - merge_video_pip(ch0_file, ch1_file, destfile); | ||
| 892 | - merged_files.push_back(destfile); | ||
| 893 | - nf++; | ||
| 894 | - | ||
| 895 | - return 0; | ||
| 896 | -} | ||
| 897 | - | ||
| 898 | 837 | ||
| 899 | int transcode_file(vector<media_info> files) | 838 | int transcode_file(vector<media_info> files) |
| 900 | { | 839 | { |
| @@ -952,10 +891,6 @@ bool is_audio_start(int index) | @@ -952,10 +891,6 @@ bool is_audio_start(int index) | ||
| 952 | return (sorted_infos[index].m_type == mt_audio && sorted_infos[index].t_type == tt_start); | 891 | return (sorted_infos[index].m_type == mt_audio && sorted_infos[index].t_type == tt_start); |
| 953 | } | 892 | } |
| 954 | 893 | ||
| 955 | -bool is_ch0_start(int index) | ||
| 956 | -{ | ||
| 957 | - return (sorted_infos[index].channel == 0 && sorted_infos[index].t_type == tt_start); | ||
| 958 | -} | ||
| 959 | 894 | ||
| 960 | 895 | ||
| 961 | int split_audio_for_video(int audio_start,vector<media_info> & result) | 896 | int split_audio_for_video(int audio_start,vector<media_info> & result) |
| @@ -1362,159 +1297,7 @@ int process_va_files() | @@ -1362,159 +1297,7 @@ int process_va_files() | ||
| 1362 | return 0; | 1297 | return 0; |
| 1363 | } | 1298 | } |
| 1364 | 1299 | ||
| 1365 | -int process_merged_files() | ||
| 1366 | -{ | ||
| 1367 | - char outputfile[1024]; | ||
| 1368 | - vector<media_info> cur_processing; | ||
| 1369 | - | ||
| 1370 | - int nOutPutFile = 0; | ||
| 1371 | - float start_time; | ||
| 1372 | - bool is_start = true; | ||
| 1373 | - string start_file; | ||
| 1374 | 1300 | ||
| 1375 | - while (sorted_infos.size()) | ||
| 1376 | - { | ||
| 1377 | - int channel = sorted_infos[0].channel; | ||
| 1378 | - if (sorted_infos[1].index == sorted_infos[0].index) | ||
| 1379 | - { | ||
| 1380 | - get_front_info(1, cur_processing); | ||
| 1381 | - transcode_file(cur_processing); | ||
| 1382 | - } | ||
| 1383 | - else if (sorted_infos[1].type_time - sorted_infos[0].type_time > 0.2) { | ||
| 1384 | - split_ch0_for_no_process(cur_processing); | ||
| 1385 | - transcode_file(cur_processing); | ||
| 1386 | - } | ||
| 1387 | - else { | ||
| 1388 | - split_ch0_for_ch1( cur_processing); | ||
| 1389 | - merge_video_pip(cur_processing); | ||
| 1390 | - } | ||
| 1391 | - //if the duration between the processed end and the start of not processed is large than 200 ms, reopen a new file | ||
| 1392 | - if (is_start){ | ||
| 1393 | - start_time = cur_processing[0].start_time; | ||
| 1394 | - start_file = cur_processing[0].name; | ||
| 1395 | - is_start = false; | ||
| 1396 | - } | ||
| 1397 | - if (is_need_output(nOutPutFile, cur_processing, start_file.c_str(), outputfile, PIP_PREFIX)){ | ||
| 1398 | - nOutPutFile++; | ||
| 1399 | - concate_files_and_adjust_timecode(outputfile); | ||
| 1400 | - save_out_info(start_time, outputfile); | ||
| 1401 | - is_start = true; | ||
| 1402 | - } | ||
| 1403 | - } | ||
| 1404 | - return 0; | ||
| 1405 | -} | ||
| 1406 | - | ||
| 1407 | -int process_record_file_to_ts() | ||
| 1408 | -{ | ||
| 1409 | - //don't split video, for a video, using merged audios to mix with it | ||
| 1410 | - //for audio, mix with video or jpg | ||
| 1411 | - char outputfile[1024]; | ||
| 1412 | - init_merge_av(); | ||
| 1413 | - | ||
| 1414 | - if (!media_files.size()){ | ||
| 1415 | - return 0; | ||
| 1416 | - } | ||
| 1417 | - | ||
| 1418 | - fp_out_info = fopen(out_info_file, "wt"); | ||
| 1419 | - | ||
| 1420 | - // judge if it is only one type | ||
| 1421 | - media_type mt = media_files[0].m_type; | ||
| 1422 | - bool only_one_type = true; | ||
| 1423 | - for (int i = 1; i < media_files.size(); i++){ | ||
| 1424 | - if (mt != media_files[i].m_type){ | ||
| 1425 | - only_one_type = false; | ||
| 1426 | - break; | ||
| 1427 | - } | ||
| 1428 | - } | ||
| 1429 | - | ||
| 1430 | - if (only_one_type){ | ||
| 1431 | - if (mt == mt_audio) { | ||
| 1432 | - for (int i = 0; i < media_files.size(); i++){ | ||
| 1433 | - fileinfo audio = media_files[i]; | ||
| 1434 | - get_output_file_name(i, audio.name.c_str(), MERGED_PREFIX, outputfile); | ||
| 1435 | - merge_audio_pic(audio.name.c_str(), blank_pic_file, outputfile); | ||
| 1436 | - save_out_info(audio.start_time, outputfile); | ||
| 1437 | - } | ||
| 1438 | - } | ||
| 1439 | - else { | ||
| 1440 | - for (int i = 0; i < media_files.size(); i++){ | ||
| 1441 | - fileinfo video = media_files[i]; | ||
| 1442 | - get_output_file_name(i, video.name.c_str(), MERGED_PREFIX, outputfile); | ||
| 1443 | - merge_video_silence(video, silence_aac_file, destfile); | ||
| 1444 | - save_out_info(video.start_time, outputfile); | ||
| 1445 | - } | ||
| 1446 | - } | ||
| 1447 | - } | ||
| 1448 | - else { | ||
| 1449 | - process_va_files(); | ||
| 1450 | - } | ||
| 1451 | - | ||
| 1452 | - if (fp_out_info) { | ||
| 1453 | - fclose(fp_out_info); | ||
| 1454 | - } | ||
| 1455 | - | ||
| 1456 | - return 0; | ||
| 1457 | -} | ||
| 1458 | - | ||
| 1459 | -int process_merged_files_to_pip_files() | ||
| 1460 | -{ | ||
| 1461 | - //don't split video, for a video, using merged audios to mix with it | ||
| 1462 | - //for audio, mix with video or jpg | ||
| 1463 | - char outputfile[1024]; | ||
| 1464 | - | ||
| 1465 | - | ||
| 1466 | - if (!media_files.size()){ | ||
| 1467 | - return 0; | ||
| 1468 | - } | ||
| 1469 | - | ||
| 1470 | - init_merge_pip(); | ||
| 1471 | - | ||
| 1472 | - fp_out_info = fopen(out_info_file, "wt"); | ||
| 1473 | - | ||
| 1474 | - process_merged_files(); | ||
| 1475 | - | ||
| 1476 | - if (fp_out_info) { | ||
| 1477 | - fclose(fp_out_info); | ||
| 1478 | - } | ||
| 1479 | - | ||
| 1480 | - return 0; | ||
| 1481 | -} | ||
| 1482 | - | ||
| 1483 | -int readfile(const char * filename) | ||
| 1484 | -{ | ||
| 1485 | - init_read_file(); | ||
| 1486 | - media_files.clear(); | ||
| 1487 | - | ||
| 1488 | - ifstream fin(filename); | ||
| 1489 | - if (!fin) { | ||
| 1490 | - return -1; | ||
| 1491 | - } | ||
| 1492 | - | ||
| 1493 | - const int LINE_LENGTH = 1000; | ||
| 1494 | - char str[LINE_LENGTH]; | ||
| 1495 | - while (fin.getline(str, LINE_LENGTH)) | ||
| 1496 | - { | ||
| 1497 | - vector < string > res; | ||
| 1498 | - split(str, " ", res); | ||
| 1499 | - if (res.size() >= 3) { | ||
| 1500 | - if (res[2] == "create"){ | ||
| 1501 | - addinfo(res[0], res[1], true); | ||
| 1502 | - } | ||
| 1503 | - else if (res[2] == "close") { | ||
| 1504 | - addinfo(res[0], res[1], false); | ||
| 1505 | - } | ||
| 1506 | - else if (res[2] == "info") { | ||
| 1507 | - if (res.size() > 5) { | ||
| 1508 | - const char * pInfo = res[5].c_str(); | ||
| 1509 | - if (!strncmp(pInfo, "rotation=", 9)){ | ||
| 1510 | - addinfo(res[0].c_str(), res[1].c_str(), pInfo + 9); | ||
| 1511 | - } | ||
| 1512 | - } | ||
| 1513 | - } | ||
| 1514 | - } | ||
| 1515 | - } | ||
| 1516 | - return 0; | ||
| 1517 | -} | ||
| 1518 | 1301 | ||
| 1519 | // parse the filename like 4165000_20180203013327202.aac | 1302 | // parse the filename like 4165000_20180203013327202.aac |
| 1520 | #define get_sub_str_to_x(x , source, len, result) strncpy(x, source, len); x[len] = 0; source += len; result = atoi(x); | 1303 | #define get_sub_str_to_x(x , source, len, result) strncpy(x, source, len); x[len] = 0; source += len; result = atoi(x); |
| @@ -1524,8 +1307,12 @@ float get_start_time_from_filename(const char * filename) | @@ -1524,8 +1307,12 @@ float get_start_time_from_filename(const char * filename) | ||
| 1524 | int year, month, day, hour, min, sec, minsec; | 1307 | int year, month, day, hour, min, sec, minsec; |
| 1525 | char buf[5]; | 1308 | char buf[5]; |
| 1526 | const char * start = strstr(filename, "_"); | 1309 | const char * start = strstr(filename, "_"); |
| 1310 | + const char * end = strstr(start + 1, "_"); | ||
| 1311 | + if (end) {//get the next | ||
| 1312 | + start = end; | ||
| 1313 | + } | ||
| 1527 | start++; | 1314 | start++; |
| 1528 | - const char * end = strstr(start, "."); | 1315 | + end = strstr(start, "."); |
| 1529 | 1316 | ||
| 1530 | get_sub_str_to_x(buf, start, 4, year); | 1317 | get_sub_str_to_x(buf, start, 4, year); |
| 1531 | 1318 | ||
| @@ -1552,37 +1339,43 @@ float get_start_time_from_filename(const char * filename) | @@ -1552,37 +1339,43 @@ float get_start_time_from_filename(const char * filename) | ||
| 1552 | return (float)(t) + minsec / 1000.0; | 1339 | return (float)(t) + minsec / 1000.0; |
| 1553 | } | 1340 | } |
| 1554 | 1341 | ||
| 1555 | -vector<string> all_input_files_for_pip; | ||
| 1556 | 1342 | ||
| 1557 | -int readfile(const char * filename, int channel) | 1343 | +int readfile(const char * filename, media_role role) |
| 1558 | { | 1344 | { |
| 1559 | - init_read_file(); | ||
| 1560 | - | ||
| 1561 | ifstream fin(filename); | 1345 | ifstream fin(filename); |
| 1562 | if (!fin) { | 1346 | if (!fin) { |
| 1563 | return -1; | 1347 | return -1; |
| 1564 | } | 1348 | } |
| 1565 | 1349 | ||
| 1350 | + float start_time = get_start_time_from_filename(filename); | ||
| 1351 | + | ||
| 1566 | const int LINE_LENGTH = 1000; | 1352 | const int LINE_LENGTH = 1000; |
| 1567 | char str[LINE_LENGTH]; | 1353 | char str[LINE_LENGTH]; |
| 1568 | - float start_time; | ||
| 1569 | - bool bstart_time = true; | ||
| 1570 | while (fin.getline(str, LINE_LENGTH)) | 1354 | while (fin.getline(str, LINE_LENGTH)) |
| 1571 | { | 1355 | { |
| 1572 | vector < string > res; | 1356 | vector < string > res; |
| 1573 | split(str, " ", res); | 1357 | split(str, " ", res); |
| 1574 | - if (res.size() == 3) { | ||
| 1575 | - if (bstart_time) { | ||
| 1576 | - start_time = get_start_time_from_filename(res[2].c_str() + strlen(MERGED_PREFIX)); | ||
| 1577 | - bstart_time = false; | 1358 | + if (res.size() >= 3) { |
| 1359 | + if (res[2] == "create"){ | ||
| 1360 | + addinfo(start_time + atof(res[0].c_str()), res[1], true, role); | ||
| 1361 | + } | ||
| 1362 | + else if (res[2] == "close") { | ||
| 1363 | + addinfo(start_time + atof(res[0].c_str()), res[1], false, role); | ||
| 1364 | + } | ||
| 1365 | + else if (res[2] == "info") { | ||
| 1366 | + if (res.size() > 5) { | ||
| 1367 | + const char * pInfo = res[5].c_str(); | ||
| 1368 | + if (!strncmp(pInfo, "rotation=", 9)){ | ||
| 1369 | + addinfo(res[0].c_str(), res[1].c_str(), pInfo + 9); | ||
| 1370 | + } | ||
| 1371 | + } | ||
| 1578 | } | 1372 | } |
| 1579 | - addinfo(atof(res[0].c_str()) + start_time ,atof(res[1].c_str()) , res[2], channel); | ||
| 1580 | - all_input_files_for_pip.push_back(res[2]); | ||
| 1581 | } | 1373 | } |
| 1582 | } | 1374 | } |
| 1583 | return 0; | 1375 | return 0; |
| 1584 | } | 1376 | } |
| 1585 | 1377 | ||
| 1378 | +vector<string> all_input_files_for_pip; | ||
| 1586 | 1379 | ||
| 1587 | void load_codec_param() | 1380 | void load_codec_param() |
| 1588 | { | 1381 | { |
| @@ -1645,7 +1438,7 @@ void get_outinfo_file_name(char * input) | @@ -1645,7 +1438,7 @@ void get_outinfo_file_name(char * input) | ||
| 1645 | strcat(out_info_file, "_out.txt"); | 1438 | strcat(out_info_file, "_out.txt"); |
| 1646 | } | 1439 | } |
| 1647 | 1440 | ||
| 1648 | -int process_record_info_to_ts(char * record_info, vector<string> & merged_info1, vector<string> & merged_info2) | 1441 | +int load_record_info(char * record_info) |
| 1649 | { | 1442 | { |
| 1650 | ifstream fin(record_info); | 1443 | ifstream fin(record_info); |
| 1651 | if (!fin) { | 1444 | if (!fin) { |
| @@ -1657,6 +1450,9 @@ int process_record_info_to_ts(char * record_info, vector<string> & merged_info1, | @@ -1657,6 +1450,9 @@ int process_record_info_to_ts(char * record_info, vector<string> & merged_info1, | ||
| 1657 | bool bInTeacher = false; | 1450 | bool bInTeacher = false; |
| 1658 | bool bInStudent = false; | 1451 | bool bInStudent = false; |
| 1659 | int nstudent = 0; | 1452 | int nstudent = 0; |
| 1453 | + | ||
| 1454 | + media_files.clear(); | ||
| 1455 | + | ||
| 1660 | while (fin.getline(str, LINE_LENGTH)) | 1456 | while (fin.getline(str, LINE_LENGTH)) |
| 1661 | { | 1457 | { |
| 1662 | if (!strncmp(str, "teacher:", 8)){ | 1458 | if (!strncmp(str, "teacher:", 8)){ |
| @@ -1673,40 +1469,26 @@ int process_record_info_to_ts(char * record_info, vector<string> & merged_info1, | @@ -1673,40 +1469,26 @@ int process_record_info_to_ts(char * record_info, vector<string> & merged_info1, | ||
| 1673 | continue;//assume the file name > 20 | 1469 | continue;//assume the file name > 20 |
| 1674 | } | 1470 | } |
| 1675 | else if (bInTeacher){ | 1471 | else if (bInTeacher){ |
| 1676 | - readfile(str); | ||
| 1677 | - get_outinfo_file_name(str); | ||
| 1678 | - merged_info1.push_back(out_info_file); | ||
| 1679 | - process_record_file_to_ts(); | 1472 | + readfile(str, mr_teacher); |
| 1680 | } | 1473 | } |
| 1681 | else if (bInStudent){ | 1474 | else if (bInStudent){ |
| 1682 | - readfile(str); | ||
| 1683 | - get_outinfo_file_name(str); | ||
| 1684 | - merged_info2.push_back(out_info_file); | ||
| 1685 | - process_record_file_to_ts(); | 1475 | + readfile(str, mr_student); |
| 1686 | } | 1476 | } |
| 1687 | } | 1477 | } |
| 1478 | + | ||
| 1479 | + unifiy_start_time(); | ||
| 1480 | + | ||
| 1481 | + add_media_infos(); | ||
| 1482 | + | ||
| 1688 | return 0; | 1483 | return 0; |
| 1689 | } | 1484 | } |
| 1690 | 1485 | ||
| 1691 | -//#define TEST | ||
| 1692 | int main(int argc, char * argv[]) | 1486 | int main(int argc, char * argv[]) |
| 1693 | { | 1487 | { |
| 1694 | -#ifdef TEST | ||
| 1695 | - const char * video = "D:\\media\\talk\\20181112\\talk915_824250397_105638\\137786519_20181112105817677.ts"; | ||
| 1696 | - const char * dest = "D:\\media\\talk\\20181112\\talk915_824250397_105638\\137786519_20181112105817677.ts.jpg"; | ||
| 1697 | - get_config_path(); | ||
| 1698 | - load_codec_param(); | ||
| 1699 | - init_merge_av(); | ||
| 1700 | - get_video_last_frame_jpeg(video, dest); | ||
| 1701 | - merge_pic_silence(dest, 1.56, "D:\\media\\talk\\20181112\\talk915_824250397_105638\\137786519_20181112105817677_last_s156.ts"); | ||
| 1702 | -#endif | ||
| 1703 | - | ||
| 1704 | if (argc < 2) { | 1488 | if (argc < 2) { |
| 1705 | - printf(" merge_pip 1.0.2\n"); | ||
| 1706 | - printf(" run ffmpeg to merge video files to one pip video according to record info file,\nusage:"); | 1489 | + printf(" merge_pip 2.0.0\n"); |
| 1490 | + printf(" merge video files to one pip video according to record info file,\nusage:"); | ||
| 1707 | printf("\n %s record_info_filename [-p] [-k]", argv[0]); | 1491 | printf("\n %s record_info_filename [-p] [-k]", argv[0]); |
| 1708 | - printf("\n -p :only print the command,don't run ffmpeg"); | ||
| 1709 | - printf("\n -k :keep the temp files"); | ||
| 1710 | printf("\n -d :individual files for different time segment"); | 1492 | printf("\n -d :individual files for different time segment"); |
| 1711 | printf("\n\n"); | 1493 | printf("\n\n"); |
| 1712 | return -1; | 1494 | return -1; |
| @@ -1716,85 +1498,598 @@ int main(int argc, char * argv[]) | @@ -1716,85 +1498,598 @@ int main(int argc, char * argv[]) | ||
| 1716 | 1498 | ||
| 1717 | load_codec_param(); | 1499 | load_codec_param(); |
| 1718 | 1500 | ||
| 1719 | - bool bmerge_files = true; | ||
| 1720 | - | ||
| 1721 | for (int i = 2; i < argc; i++){ | 1501 | for (int i = 2; i < argc; i++){ |
| 1722 | - if (!strcmp(argv[i], "-p")){ | ||
| 1723 | - only_print = true; | ||
| 1724 | - } | ||
| 1725 | - else if (!strcmp(argv[i], "-k")){ | ||
| 1726 | - keep_tmp_files = true; | ||
| 1727 | - } | ||
| 1728 | - else if (!strcmp(argv[i], "-n")){ | ||
| 1729 | - bmerge_files = false; | ||
| 1730 | - } | ||
| 1731 | - else if (!strcmp(argv[i], "-d")){ | 1502 | + if (!strcmp(argv[i], "-d")){ |
| 1732 | out_one_video = false; | 1503 | out_one_video = false; |
| 1733 | } | 1504 | } |
| 1734 | } | 1505 | } |
| 1735 | 1506 | ||
| 1736 | - vector<string> merged_info1; | ||
| 1737 | - vector<string> merged_info2; | ||
| 1738 | -#if 0 | ||
| 1739 | - if (bmerge_files) { | ||
| 1740 | - if (readfile(argv[1]) < 0) { | ||
| 1741 | - printf("open file: %s error", argv[1]); | ||
| 1742 | - return -2; | ||
| 1743 | - } | ||
| 1744 | - | ||
| 1745 | - get_outinfo_file_name(argv[1]); | ||
| 1746 | - strcpy(merged_info1, out_info_file); | ||
| 1747 | - process_record_file_to_ts(); | ||
| 1748 | - | ||
| 1749 | - | ||
| 1750 | - | ||
| 1751 | - if (readfile(argv[2]) < 0) { | ||
| 1752 | - printf("open file: %s error", argv[1]); | ||
| 1753 | - return -2; | ||
| 1754 | - } | ||
| 1755 | - | ||
| 1756 | - get_outinfo_file_name(argv[2]); | ||
| 1757 | - strcpy(merged_info2, out_info_file); | ||
| 1758 | - process_record_file_to_ts(); | ||
| 1759 | - } | ||
| 1760 | - else { | ||
| 1761 | - strcpy(merged_info1, argv[1]); | ||
| 1762 | - strcpy(merged_info2, argv[2]); | ||
| 1763 | - } | ||
| 1764 | -#else | ||
| 1765 | - process_record_info_to_ts(argv[1], merged_info1, merged_info2); | ||
| 1766 | - | ||
| 1767 | -#endif | ||
| 1768 | - | ||
| 1769 | - media_files.clear(); | ||
| 1770 | - for (int i = 0; i < merged_info1.size(); i++) { | ||
| 1771 | - if (readfile(merged_info1[i].c_str(), 0) < 0) { | ||
| 1772 | - printf("open file: %s error", merged_info1[i].c_str()); | ||
| 1773 | - return -2; | ||
| 1774 | - } | ||
| 1775 | - } | ||
| 1776 | - | ||
| 1777 | - for (int i = 0; i < merged_info2.size(); i++) { | ||
| 1778 | - if (readfile(merged_info2[i].c_str(), 1) < 0) { | ||
| 1779 | - printf("open file: %s error", merged_info2[i].c_str()); | ||
| 1780 | - return -2; | ||
| 1781 | - } | ||
| 1782 | - } | ||
| 1783 | - | ||
| 1784 | -#if 0 | ||
| 1785 | - get_outinfo_file_name(argv[1], argv[2]); | ||
| 1786 | -#else | ||
| 1787 | - get_outinfo_file_name(argv[1]); | ||
| 1788 | -#endif | ||
| 1789 | - | ||
| 1790 | - process_merged_files_to_pip_files(); | ||
| 1791 | - | ||
| 1792 | - if (!keep_tmp_files && bmerge_files) { | ||
| 1793 | - removefiles(all_input_files_for_pip); | ||
| 1794 | - removefiles(merged_info1); | ||
| 1795 | - removefiles(merged_info2); | ||
| 1796 | - } | ||
| 1797 | - | ||
| 1798 | - return 0; | ||
| 1799 | -} | 1507 | + load_record_info(argv[1]); |
| 1508 | +} | ||
| 1509 | + | ||
| 1510 | + | ||
| 1511 | +#define __STDC_FORMAT_MACROS | ||
| 1512 | +#include <stdint.h> | ||
| 1513 | +#include <inttypes.h> | ||
| 1514 | +extern "C" { | ||
| 1515 | +#include <libavcodec/avcodec.h> | ||
| 1516 | +#include <libavformat/avformat.h> | ||
| 1517 | +#include <libavfilter/avfiltergraph.h> | ||
| 1518 | +#include <libavfilter/buffersink.h> | ||
| 1519 | +#include <libavfilter/buffersrc.h> | ||
| 1520 | +#include <libavutil/opt.h> | ||
| 1521 | +#include <libavutil/pixdesc.h> | ||
| 1522 | +} | ||
| 1523 | +#ifdef WIN32 | ||
| 1524 | +#pragma comment(lib, "avcodec.lib") | ||
| 1525 | +#pragma comment(lib, "avdevice.lib") | ||
| 1526 | +#pragma comment(lib, "avfilter.lib") | ||
| 1527 | +#pragma comment(lib, "avformat.lib") | ||
| 1528 | +#pragma comment(lib, "avutil.lib") | ||
| 1529 | +#pragma comment(lib, "postproc.lib") | ||
| 1530 | +#pragma comment(lib, "swresample.lib") | ||
| 1531 | +#pragma comment(lib, "swscale.lib") | ||
| 1532 | +#endif | ||
| 1533 | + | ||
| 1534 | +#if _MSC_VER | ||
| 1535 | +#define snprintf _snprintf | ||
| 1536 | +#define PRIu64 "I64u" | ||
| 1537 | +#define PRId64 "I64d" | ||
| 1538 | +#define PRIx64 "I64x" | ||
| 1539 | +#define PRIX64 "I64X" | ||
| 1540 | +#endif | ||
| 1541 | + | ||
| 1542 | + | ||
| 1543 | +static AVFormatContext *ifmt_ctx; | ||
| 1544 | +static AVFormatContext *ofmt_ctx; | ||
| 1545 | +typedef struct FilteringContext { | ||
| 1546 | + AVFilterContext *buffersink_ctx; | ||
| 1547 | + AVFilterContext *buffersrc_ctx; | ||
| 1548 | + AVFilterGraph *filter_graph; | ||
| 1549 | +} FilteringContext; | ||
| 1550 | +static FilteringContext *filter_ctx; | ||
| 1551 | + | ||
| 1552 | +static int open_input_file(const char *filename) | ||
| 1553 | +{ | ||
| 1554 | + int ret; | ||
| 1555 | + unsigned int i; | ||
| 1556 | + | ||
| 1557 | + ifmt_ctx = NULL; | ||
| 1558 | + if ((ret = avformat_open_input(&ifmt_ctx, filename, NULL, NULL)) < 0) { | ||
| 1559 | + av_log(NULL, AV_LOG_ERROR, "Cannot open input file\n"); | ||
| 1560 | + return ret; | ||
| 1561 | + } | ||
| 1562 | + | ||
| 1563 | + if ((ret = avformat_find_stream_info(ifmt_ctx, NULL)) < 0) { | ||
| 1564 | + av_log(NULL, AV_LOG_ERROR, "Cannot find stream information\n"); | ||
| 1565 | + return ret; | ||
| 1566 | + } | ||
| 1567 | + | ||
| 1568 | + for (i = 0; i < ifmt_ctx->nb_streams; i++) { | ||
| 1569 | + AVStream *stream; | ||
| 1570 | + AVCodecContext *codec_ctx; | ||
| 1571 | + stream = ifmt_ctx->streams[i]; | ||
| 1572 | + codec_ctx = stream->codec; | ||
| 1573 | + /* Reencode video & audio and remux subtitles etc. */ | ||
| 1574 | + if (codec_ctx->codec_type == AVMEDIA_TYPE_VIDEO | ||
| 1575 | + || codec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { | ||
| 1576 | + /* Open decoder */ | ||
| 1577 | + ret = avcodec_open2(codec_ctx, | ||
| 1578 | + avcodec_find_decoder(codec_ctx->codec_id), NULL); | ||
| 1579 | + if (ret < 0) { | ||
| 1580 | + av_log(NULL, AV_LOG_ERROR, "Failed to open decoder for stream #%u\n", i); | ||
| 1581 | + return ret; | ||
| 1582 | + } | ||
| 1583 | + } | ||
| 1584 | + } | ||
| 1585 | + | ||
| 1586 | + av_dump_format(ifmt_ctx, 0, filename, 0); | ||
| 1587 | + return 0; | ||
| 1588 | +} | ||
| 1589 | + | ||
| 1590 | +static int open_output_file(const char *filename) | ||
| 1591 | +{ | ||
| 1592 | + AVStream *out_stream; | ||
| 1593 | + AVStream *in_stream; | ||
| 1594 | + AVCodecContext *dec_ctx, *enc_ctx; | ||
| 1595 | + AVCodec *encoder; | ||
| 1596 | + int ret; | ||
| 1597 | + unsigned int i; | ||
| 1598 | + | ||
| 1599 | + ofmt_ctx = NULL; | ||
| 1600 | + avformat_alloc_output_context2(&ofmt_ctx, NULL, NULL, filename); | ||
| 1601 | + if (!ofmt_ctx) { | ||
| 1602 | + av_log(NULL, AV_LOG_ERROR, "Could not create output context\n"); | ||
| 1603 | + return AVERROR_UNKNOWN; | ||
| 1604 | + } | ||
| 1605 | + | ||
| 1606 | + | ||
| 1607 | + for (i = 0; i < ifmt_ctx->nb_streams; i++) { | ||
| 1608 | + out_stream = avformat_new_stream(ofmt_ctx, NULL); | ||
| 1609 | + if (!out_stream) { | ||
| 1610 | + av_log(NULL, AV_LOG_ERROR, "Failed allocating output stream\n"); | ||
| 1611 | + return AVERROR_UNKNOWN; | ||
| 1612 | + } | ||
| 1613 | + | ||
| 1614 | + in_stream = ifmt_ctx->streams[i]; | ||
| 1615 | + dec_ctx = in_stream->codec; | ||
| 1616 | + enc_ctx = out_stream->codec; | ||
| 1617 | + | ||
| 1618 | + if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO | ||
| 1619 | + || dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { | ||
| 1620 | + /* in this example, we choose transcoding to same codec */ | ||
| 1621 | + encoder = avcodec_find_encoder(dec_ctx->codec_id); | ||
| 1622 | + if (!encoder) { | ||
| 1623 | + av_log(NULL, AV_LOG_FATAL, "Necessary encoder not found\n"); | ||
| 1624 | + return AVERROR_INVALIDDATA; | ||
| 1625 | + } | ||
| 1626 | + | ||
| 1627 | + /* In this example, we transcode to same properties (picture size, | ||
| 1628 | + * sample rate etc.). These properties can be changed for output | ||
| 1629 | + * streams easily using filters */ | ||
| 1630 | + if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
| 1631 | + enc_ctx->height = dec_ctx->height; | ||
| 1632 | + enc_ctx->width = dec_ctx->width; | ||
| 1633 | + enc_ctx->sample_aspect_ratio = dec_ctx->sample_aspect_ratio; | ||
| 1634 | + /* take first format from list of supported formats */ | ||
| 1635 | + enc_ctx->pix_fmt = encoder->pix_fmts[0]; | ||
| 1636 | + /* video time_base can be set to whatever is handy and supported by encoder */ | ||
| 1637 | + enc_ctx->time_base = dec_ctx->time_base; | ||
| 1638 | + } | ||
| 1639 | + else { | ||
| 1640 | + enc_ctx->sample_rate = dec_ctx->sample_rate; | ||
| 1641 | + enc_ctx->channel_layout = dec_ctx->channel_layout; | ||
| 1642 | + enc_ctx->channels = av_get_channel_layout_nb_channels(enc_ctx->channel_layout); | ||
| 1643 | + /* take first format from list of supported formats */ | ||
| 1644 | + enc_ctx->sample_fmt = encoder->sample_fmts[0]; | ||
| 1645 | + enc_ctx->time_base.num = 1; | ||
| 1646 | + enc_ctx->time_base.den = enc_ctx->sample_rate; | ||
| 1647 | + } | ||
| 1648 | + | ||
| 1649 | + /* Third parameter can be used to pass settings to encoder */ | ||
| 1650 | + ret = avcodec_open2(enc_ctx, encoder, NULL); | ||
| 1651 | + if (ret < 0) { | ||
| 1652 | + av_log(NULL, AV_LOG_ERROR, "Cannot open video encoder for stream #%u\n", i); | ||
| 1653 | + return ret; | ||
| 1654 | + } | ||
| 1655 | + } | ||
| 1656 | + else if (dec_ctx->codec_type == AVMEDIA_TYPE_UNKNOWN) { | ||
| 1657 | + av_log(NULL, AV_LOG_FATAL, "Elementary stream #%d is of unknown type, cannot proceed\n", i); | ||
| 1658 | + return AVERROR_INVALIDDATA; | ||
| 1659 | + } | ||
| 1660 | + else { | ||
| 1661 | + /* if this stream must be remuxed */ | ||
| 1662 | + ret = avcodec_copy_context(ofmt_ctx->streams[i]->codec, | ||
| 1663 | + ifmt_ctx->streams[i]->codec); | ||
| 1664 | + if (ret < 0) { | ||
| 1665 | + av_log(NULL, AV_LOG_ERROR, "Copying stream context failed\n"); | ||
| 1666 | + return ret; | ||
| 1667 | + } | ||
| 1668 | + } | ||
| 1669 | + | ||
| 1670 | + if (ofmt_ctx->oformat->flags & AVFMT_GLOBALHEADER) | ||
| 1671 | + enc_ctx->flags |= CODEC_FLAG_GLOBAL_HEADER; | ||
| 1672 | + | ||
| 1673 | + } | ||
| 1674 | + av_dump_format(ofmt_ctx, 0, filename, 1); | ||
| 1675 | + | ||
| 1676 | + if (!(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) { | ||
| 1677 | + ret = avio_open(&ofmt_ctx->pb, filename, AVIO_FLAG_WRITE); | ||
| 1678 | + if (ret < 0) { | ||
| 1679 | + av_log(NULL, AV_LOG_ERROR, "Could not open output file '%s'", filename); | ||
| 1680 | + return ret; | ||
| 1681 | + } | ||
| 1682 | + } | ||
| 1683 | + | ||
| 1684 | + /* init muxer, write output file header */ | ||
| 1685 | + ret = avformat_write_header(ofmt_ctx, NULL); | ||
| 1686 | + if (ret < 0) { | ||
| 1687 | + av_log(NULL, AV_LOG_ERROR, "Error occurred when opening output file\n"); | ||
| 1688 | + return ret; | ||
| 1689 | + } | ||
| 1690 | + | ||
| 1691 | + return 0; | ||
| 1692 | +} | ||
| 1693 | + | ||
| 1694 | +static int init_filter(FilteringContext* fctx, AVCodecContext *dec_ctx, | ||
| 1695 | + AVCodecContext *enc_ctx, const char *filter_spec) | ||
| 1696 | +{ | ||
| 1697 | + char args[512]; | ||
| 1698 | + int ret = 0; | ||
| 1699 | + AVFilter *buffersrc = NULL; | ||
| 1700 | + AVFilter *buffersink = NULL; | ||
| 1701 | + AVFilterContext *buffersrc_ctx = NULL; | ||
| 1702 | + AVFilterContext *buffersink_ctx = NULL; | ||
| 1703 | + AVFilterInOut *outputs = avfilter_inout_alloc(); | ||
| 1704 | + AVFilterInOut *inputs = avfilter_inout_alloc(); | ||
| 1705 | + AVFilterGraph *filter_graph = avfilter_graph_alloc(); | ||
| 1706 | + | ||
| 1707 | + if (!outputs || !inputs || !filter_graph) { | ||
| 1708 | + ret = AVERROR(ENOMEM); | ||
| 1709 | + goto end; | ||
| 1710 | + } | ||
| 1711 | + | ||
| 1712 | + if (dec_ctx->codec_type == AVMEDIA_TYPE_VIDEO) { | ||
| 1713 | + buffersrc = avfilter_get_by_name("buffer"); | ||
| 1714 | + buffersink = avfilter_get_by_name("buffersink"); | ||
| 1715 | + if (!buffersrc || !buffersink) { | ||
| 1716 | + av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n"); | ||
| 1717 | + ret = AVERROR_UNKNOWN; | ||
| 1718 | + goto end; | ||
| 1719 | + } | ||
| 1720 | + | ||
| 1721 | + snprintf(args, sizeof(args), | ||
| 1722 | + "video_size=%dx%d:pix_fmt=%d:time_base=%d/%d:pixel_aspect=%d/%d", | ||
| 1723 | + dec_ctx->width, dec_ctx->height, dec_ctx->pix_fmt, | ||
| 1724 | + dec_ctx->time_base.num, dec_ctx->time_base.den, | ||
| 1725 | + dec_ctx->sample_aspect_ratio.num, | ||
| 1726 | + dec_ctx->sample_aspect_ratio.den); | ||
| 1727 | + | ||
| 1728 | + ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", | ||
| 1729 | + args, NULL, filter_graph); | ||
| 1730 | + if (ret < 0) { | ||
| 1731 | + av_log(NULL, AV_LOG_ERROR, "Cannot create buffer source\n"); | ||
| 1732 | + goto end; | ||
| 1733 | + } | ||
| 1734 | + | ||
| 1735 | + ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", | ||
| 1736 | + NULL, NULL, filter_graph); | ||
| 1737 | + if (ret < 0) { | ||
| 1738 | + av_log(NULL, AV_LOG_ERROR, "Cannot create buffer sink\n"); | ||
| 1739 | + goto end; | ||
| 1740 | + } | ||
| 1741 | + | ||
| 1742 | + ret = av_opt_set_bin(buffersink_ctx, "pix_fmts", | ||
| 1743 | + (uint8_t*)&enc_ctx->pix_fmt, sizeof(enc_ctx->pix_fmt), | ||
| 1744 | + AV_OPT_SEARCH_CHILDREN); | ||
| 1745 | + if (ret < 0) { | ||
| 1746 | + av_log(NULL, AV_LOG_ERROR, "Cannot set output pixel format\n"); | ||
| 1747 | + goto end; | ||
| 1748 | + } | ||
| 1749 | + } | ||
| 1750 | + else if (dec_ctx->codec_type == AVMEDIA_TYPE_AUDIO) { | ||
| 1751 | + buffersrc = avfilter_get_by_name("abuffer"); | ||
| 1752 | + buffersink = avfilter_get_by_name("abuffersink"); | ||
| 1753 | + if (!buffersrc || !buffersink) { | ||
| 1754 | + av_log(NULL, AV_LOG_ERROR, "filtering source or sink element not found\n"); | ||
| 1755 | + ret = AVERROR_UNKNOWN; | ||
| 1756 | + goto end; | ||
| 1757 | + } | ||
| 1758 | + | ||
| 1759 | + if (!dec_ctx->channel_layout) | ||
| 1760 | + dec_ctx->channel_layout = | ||
| 1761 | + av_get_default_channel_layout(dec_ctx->channels); | ||
| 1762 | + sprintf(args, //sizeof(args), | ||
| 1763 | + "time_base=%d/%d:sample_rate=%d:sample_fmt=%s:channel_layout=0x%"PRIx64, | ||
| 1764 | + dec_ctx->time_base.num, dec_ctx->time_base.den, dec_ctx->sample_rate, | ||
| 1765 | + av_get_sample_fmt_name(dec_ctx->sample_fmt), | ||
| 1766 | + dec_ctx->channel_layout); | ||
| 1767 | + ret = avfilter_graph_create_filter(&buffersrc_ctx, buffersrc, "in", | ||
| 1768 | + args, NULL, filter_graph); | ||
| 1769 | + if (ret < 0) { | ||
| 1770 | + av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer source\n"); | ||
| 1771 | + goto end; | ||
| 1772 | + } | ||
| 1773 | + | ||
| 1774 | + ret = avfilter_graph_create_filter(&buffersink_ctx, buffersink, "out", | ||
| 1775 | + NULL, NULL, filter_graph); | ||
| 1776 | + if (ret < 0) { | ||
| 1777 | + av_log(NULL, AV_LOG_ERROR, "Cannot create audio buffer sink\n"); | ||
| 1778 | + goto end; | ||
| 1779 | + } | ||
| 1780 | + | ||
| 1781 | + ret = av_opt_set_bin(buffersink_ctx, "sample_fmts", | ||
| 1782 | + (uint8_t*)&enc_ctx->sample_fmt, sizeof(enc_ctx->sample_fmt), | ||
| 1783 | + AV_OPT_SEARCH_CHILDREN); | ||
| 1784 | + if (ret < 0) { | ||
| 1785 | + av_log(NULL, AV_LOG_ERROR, "Cannot set output sample format\n"); | ||
| 1786 | + goto end; | ||
| 1787 | + } | ||
| 1788 | + | ||
| 1789 | + ret = av_opt_set_bin(buffersink_ctx, "channel_layouts", | ||
| 1790 | + (uint8_t*)&enc_ctx->channel_layout, | ||
| 1791 | + sizeof(enc_ctx->channel_layout), AV_OPT_SEARCH_CHILDREN); | ||
| 1792 | + if (ret < 0) { | ||
| 1793 | + av_log(NULL, AV_LOG_ERROR, "Cannot set output channel layout\n"); | ||
| 1794 | + goto end; | ||
| 1795 | + } | ||
| 1796 | + | ||
| 1797 | + ret = av_opt_set_bin(buffersink_ctx, "sample_rates", | ||
| 1798 | + (uint8_t*)&enc_ctx->sample_rate, sizeof(enc_ctx->sample_rate), | ||
| 1799 | + AV_OPT_SEARCH_CHILDREN); | ||
| 1800 | + if (ret < 0) { | ||
| 1801 | + av_log(NULL, AV_LOG_ERROR, "Cannot set output sample rate\n"); | ||
| 1802 | + goto end; | ||
| 1803 | + } | ||
| 1804 | + } | ||
| 1805 | + else { | ||
| 1806 | + ret = AVERROR_UNKNOWN; | ||
| 1807 | + goto end; | ||
| 1808 | + } | ||
| 1809 | + | ||
| 1810 | + /* Endpoints for the filter graph. */ | ||
| 1811 | + outputs->name = av_strdup("in"); | ||
| 1812 | + outputs->filter_ctx = buffersrc_ctx; | ||
| 1813 | + outputs->pad_idx = 0; | ||
| 1814 | + outputs->next = NULL; | ||
| 1815 | + | ||
| 1816 | + inputs->name = av_strdup("out"); | ||
| 1817 | + inputs->filter_ctx = buffersink_ctx; | ||
| 1818 | + inputs->pad_idx = 0; | ||
| 1819 | + inputs->next = NULL; | ||
| 1820 | + | ||
| 1821 | + if (!outputs->name || !inputs->name) { | ||
| 1822 | + ret = AVERROR(ENOMEM); | ||
| 1823 | + goto end; | ||
| 1824 | + } | ||
| 1825 | + | ||
| 1826 | + if ((ret = avfilter_graph_parse_ptr(filter_graph, filter_spec, | ||
| 1827 | + &inputs, &outputs, NULL)) < 0) | ||
| 1828 | + goto end; | ||
| 1829 | + | ||
| 1830 | + if ((ret = avfilter_graph_config(filter_graph, NULL)) < 0) | ||
| 1831 | + goto end; | ||
| 1832 | + | ||
| 1833 | + /* Fill FilteringContext */ | ||
| 1834 | + fctx->buffersrc_ctx = buffersrc_ctx; | ||
| 1835 | + fctx->buffersink_ctx = buffersink_ctx; | ||
| 1836 | + fctx->filter_graph = filter_graph; | ||
| 1837 | + | ||
| 1838 | +end: | ||
| 1839 | + avfilter_inout_free(&inputs); | ||
| 1840 | + avfilter_inout_free(&outputs); | ||
| 1841 | + | ||
| 1842 | + return ret; | ||
| 1843 | +} | ||
| 1844 | + | ||
| 1845 | +static int init_filters(void) | ||
| 1846 | +{ | ||
| 1847 | + const char *filter_spec; | ||
| 1848 | + unsigned int i; | ||
| 1849 | + int ret; | ||
| 1850 | + filter_ctx = (FilteringContext *)av_malloc_array(ifmt_ctx->nb_streams, sizeof(*filter_ctx)); | ||
| 1851 | + if (!filter_ctx) | ||
| 1852 | + return AVERROR(ENOMEM); | ||
| 1853 | + | ||
| 1854 | + for (i = 0; i < ifmt_ctx->nb_streams; i++) { | ||
| 1855 | + filter_ctx[i].buffersrc_ctx = NULL; | ||
| 1856 | + filter_ctx[i].buffersink_ctx = NULL; | ||
| 1857 | + filter_ctx[i].filter_graph = NULL; | ||
| 1858 | + if (!(ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO | ||
| 1859 | + || ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)) | ||
| 1860 | + continue; | ||
| 1861 | + | ||
| 1862 | + | ||
| 1863 | + if (ifmt_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO) | ||
| 1864 | + filter_spec = "null"; /* passthrough (dummy) filter for video */ | ||
| 1865 | + else | ||
| 1866 | + filter_spec = "anull"; /* passthrough (dummy) filter for audio */ | ||
| 1867 | + ret = init_filter(&filter_ctx[i], ifmt_ctx->streams[i]->codec, | ||
| 1868 | + ofmt_ctx->streams[i]->codec, filter_spec); | ||
| 1869 | + if (ret) | ||
| 1870 | + return ret; | ||
| 1871 | + } | ||
| 1872 | + return 0; | ||
| 1873 | +} | ||
| 1874 | + | ||
| 1875 | +static int encode_write_frame(AVFrame *filt_frame, unsigned int stream_index, int *got_frame) { | ||
| 1876 | + int ret; | ||
| 1877 | + int got_frame_local; | ||
| 1878 | + AVPacket enc_pkt; | ||
| 1879 | + int(*enc_func)(AVCodecContext *, AVPacket *, const AVFrame *, int *) = | ||
| 1880 | + (ifmt_ctx->streams[stream_index]->codec->codec_type == | ||
| 1881 | + AVMEDIA_TYPE_VIDEO) ? avcodec_encode_video2 : avcodec_encode_audio2; | ||
| 1882 | + | ||
| 1883 | + if (!got_frame) | ||
| 1884 | + got_frame = &got_frame_local; | ||
| 1885 | + | ||
| 1886 | + av_log(NULL, AV_LOG_INFO, "Encoding frame\n"); | ||
| 1887 | + /* encode filtered frame */ | ||
| 1888 | + enc_pkt.data = NULL; | ||
| 1889 | + enc_pkt.size = 0; | ||
| 1890 | + av_init_packet(&enc_pkt); | ||
| 1891 | + ret = enc_func(ofmt_ctx->streams[stream_index]->codec, &enc_pkt, | ||
| 1892 | + filt_frame, got_frame); | ||
| 1893 | + av_frame_free(&filt_frame); | ||
| 1894 | + if (ret < 0) | ||
| 1895 | + return ret; | ||
| 1896 | + if (!(*got_frame)) | ||
| 1897 | + return 0; | ||
| 1898 | + | ||
| 1899 | + /* prepare packet for muxing */ | ||
| 1900 | + enc_pkt.stream_index = stream_index; | ||
| 1901 | + av_packet_rescale_ts(&enc_pkt, | ||
| 1902 | + ofmt_ctx->streams[stream_index]->codec->time_base, | ||
| 1903 | + ofmt_ctx->streams[stream_index]->time_base); | ||
| 1904 | + | ||
| 1905 | + av_log(NULL, AV_LOG_DEBUG, "Muxing frame\n"); | ||
| 1906 | + /* mux encoded frame */ | ||
| 1907 | + ret = av_interleaved_write_frame(ofmt_ctx, &enc_pkt); | ||
| 1908 | + return ret; | ||
| 1909 | +} | ||
| 1910 | + | ||
| 1911 | +static int filter_encode_write_frame(AVFrame *frame, unsigned int stream_index) | ||
| 1912 | +{ | ||
| 1913 | + int ret; | ||
| 1914 | + AVFrame *filt_frame; | ||
| 1915 | + | ||
| 1916 | + av_log(NULL, AV_LOG_INFO, "Pushing decoded frame to filters\n"); | ||
| 1917 | + /* push the decoded frame into the filtergraph */ | ||
| 1918 | + ret = av_buffersrc_add_frame_flags(filter_ctx[stream_index].buffersrc_ctx, | ||
| 1919 | + frame, 0); | ||
| 1920 | + if (ret < 0) { | ||
| 1921 | + av_log(NULL, AV_LOG_ERROR, "Error while feeding the filtergraph\n"); | ||
| 1922 | + return ret; | ||
| 1923 | + } | ||
| 1924 | + | ||
| 1925 | + /* pull filtered frames from the filtergraph */ | ||
| 1926 | + while (1) { | ||
| 1927 | + filt_frame = av_frame_alloc(); | ||
| 1928 | + if (!filt_frame) { | ||
| 1929 | + ret = AVERROR(ENOMEM); | ||
| 1930 | + break; | ||
| 1931 | + } | ||
| 1932 | + av_log(NULL, AV_LOG_INFO, "Pulling filtered frame from filters\n"); | ||
| 1933 | + ret = av_buffersink_get_frame(filter_ctx[stream_index].buffersink_ctx, | ||
| 1934 | + filt_frame); | ||
| 1935 | + if (ret < 0) { | ||
| 1936 | + /* if no more frames for output - returns AVERROR(EAGAIN) | ||
| 1937 | + * if flushed and no more frames for output - returns AVERROR_EOF | ||
| 1938 | + * rewrite retcode to 0 to show it as normal procedure completion | ||
| 1939 | + */ | ||
| 1940 | + if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) | ||
| 1941 | + ret = 0; | ||
| 1942 | + av_frame_free(&filt_frame); | ||
| 1943 | + break; | ||
| 1944 | + } | ||
| 1945 | + | ||
| 1946 | + filt_frame->pict_type = AV_PICTURE_TYPE_NONE; | ||
| 1947 | + ret = encode_write_frame(filt_frame, stream_index, NULL); | ||
| 1948 | + if (ret < 0) | ||
| 1949 | + break; | ||
| 1950 | + } | ||
| 1951 | + | ||
| 1952 | + return ret; | ||
| 1953 | +} | ||
| 1954 | + | ||
| 1955 | +static int flush_encoder(unsigned int stream_index) | ||
| 1956 | +{ | ||
| 1957 | + int ret; | ||
| 1958 | + int got_frame; | ||
| 1959 | + | ||
| 1960 | + if (!(ofmt_ctx->streams[stream_index]->codec->codec->capabilities & | ||
| 1961 | + CODEC_CAP_DELAY)) | ||
| 1962 | + return 0; | ||
| 1963 | + | ||
| 1964 | + while (1) { | ||
| 1965 | + av_log(NULL, AV_LOG_INFO, "Flushing stream #%u encoder\n", stream_index); | ||
| 1966 | + ret = encode_write_frame(NULL, stream_index, &got_frame); | ||
| 1967 | + if (ret < 0) | ||
| 1968 | + break; | ||
| 1969 | + if (!got_frame) | ||
| 1970 | + return 0; | ||
| 1971 | + } | ||
| 1972 | + return ret; | ||
| 1973 | +} | ||
| 1974 | + | ||
| 1975 | +int transcode(int argc, char *argv[]){ | ||
| 1976 | + int ret; | ||
| 1977 | + AVPacket packet; | ||
| 1978 | + AVFrame *frame = NULL; | ||
| 1979 | + enum AVMediaType type; | ||
| 1980 | + unsigned int stream_index; | ||
| 1981 | + unsigned int i; | ||
| 1982 | + int got_frame; | ||
| 1983 | + int(*dec_func)(AVCodecContext *, AVFrame *, int *, const AVPacket *); | ||
| 1984 | + memset(&packet, 0, sizeof(AVPacket)); | ||
| 1985 | + | ||
| 1986 | + if (argc != 3) { | ||
| 1987 | + av_log(NULL, AV_LOG_ERROR, "Usage: %s <input file> <output file>\n", argv[0]); | ||
| 1988 | + return 1; | ||
| 1989 | + } | ||
| 1990 | + | ||
| 1991 | + av_register_all(); | ||
| 1992 | + avfilter_register_all(); | ||
| 1993 | + | ||
| 1994 | + if ((ret = open_input_file(argv[1])) < 0) | ||
| 1995 | + goto end; | ||
| 1996 | + if ((ret = open_output_file(argv[2])) < 0) | ||
| 1997 | + goto end; | ||
| 1998 | + if ((ret = init_filters()) < 0) | ||
| 1999 | + goto end; | ||
| 2000 | + | ||
| 2001 | + /* read all packets */ | ||
| 2002 | + while (1) { | ||
| 2003 | + if ((ret = av_read_frame(ifmt_ctx, &packet)) < 0) | ||
| 2004 | + break; | ||
| 2005 | + stream_index = packet.stream_index; | ||
| 2006 | + type = ifmt_ctx->streams[packet.stream_index]->codec->codec_type; | ||
| 2007 | + av_log(NULL, AV_LOG_DEBUG, "Demuxer gave frame of stream_index %u\n", | ||
| 2008 | + stream_index); | ||
| 2009 | + | ||
| 2010 | + if (filter_ctx[stream_index].filter_graph) { | ||
| 2011 | + av_log(NULL, AV_LOG_DEBUG, "Going to reencode&filter the frame\n"); | ||
| 2012 | + frame = av_frame_alloc(); | ||
| 2013 | + if (!frame) { | ||
| 2014 | + ret = AVERROR(ENOMEM); | ||
| 2015 | + break; | ||
| 2016 | + } | ||
| 2017 | + av_packet_rescale_ts(&packet, | ||
| 2018 | + ifmt_ctx->streams[stream_index]->time_base, | ||
| 2019 | + ifmt_ctx->streams[stream_index]->codec->time_base); | ||
| 2020 | + dec_func = (type == AVMEDIA_TYPE_VIDEO) ? avcodec_decode_video2 : | ||
| 2021 | + avcodec_decode_audio4; | ||
| 2022 | + ret = dec_func(ifmt_ctx->streams[stream_index]->codec, frame, | ||
| 2023 | + &got_frame, &packet); | ||
| 2024 | + if (ret < 0) { | ||
| 2025 | + av_frame_free(&frame); | ||
| 2026 | + av_log(NULL, AV_LOG_ERROR, "Decoding failed\n"); | ||
| 2027 | + break; | ||
| 2028 | + } | ||
| 2029 | + | ||
| 2030 | + if (got_frame) { | ||
| 2031 | + frame->pts = av_frame_get_best_effort_timestamp(frame); | ||
| 2032 | + ret = filter_encode_write_frame(frame, stream_index); | ||
| 2033 | + av_frame_free(&frame); | ||
| 2034 | + if (ret < 0) | ||
| 2035 | + goto end; | ||
| 2036 | + } | ||
| 2037 | + else { | ||
| 2038 | + av_frame_free(&frame); | ||
| 2039 | + } | ||
| 2040 | + } | ||
| 2041 | + else { | ||
| 2042 | + /* remux this frame without reencoding */ | ||
| 2043 | + av_packet_rescale_ts(&packet, | ||
| 2044 | + ifmt_ctx->streams[stream_index]->time_base, | ||
| 2045 | + ofmt_ctx->streams[stream_index]->time_base); | ||
| 2046 | + | ||
| 2047 | + ret = av_interleaved_write_frame(ofmt_ctx, &packet); | ||
| 2048 | + if (ret < 0) | ||
| 2049 | + goto end; | ||
| 2050 | + } | ||
| 2051 | + av_packet_unref(&packet); | ||
| 2052 | + } | ||
| 2053 | + | ||
| 2054 | + /* flush filters and encoders */ | ||
| 2055 | + for (i = 0; i < ifmt_ctx->nb_streams; i++) { | ||
| 2056 | + /* flush filter */ | ||
| 2057 | + if (!filter_ctx[i].filter_graph) | ||
| 2058 | + continue; | ||
| 2059 | + ret = filter_encode_write_frame(NULL, i); | ||
| 2060 | + if (ret < 0) { | ||
| 2061 | + av_log(NULL, AV_LOG_ERROR, "Flushing filter failed\n"); | ||
| 2062 | + goto end; | ||
| 2063 | + } | ||
| 2064 | + | ||
| 2065 | + /* flush encoder */ | ||
| 2066 | + ret = flush_encoder(i); | ||
| 2067 | + if (ret < 0) { | ||
| 2068 | + av_log(NULL, AV_LOG_ERROR, "Flushing encoder failed\n"); | ||
| 2069 | + goto end; | ||
| 2070 | + } | ||
| 2071 | + } | ||
| 2072 | + | ||
| 2073 | + av_write_trailer(ofmt_ctx); | ||
| 2074 | +end: | ||
| 2075 | + av_packet_unref(&packet); | ||
| 2076 | + av_frame_free(&frame); | ||
| 2077 | + for (i = 0; i < ifmt_ctx->nb_streams; i++) { | ||
| 2078 | + avcodec_close(ifmt_ctx->streams[i]->codec); | ||
| 2079 | + if (ofmt_ctx && ofmt_ctx->nb_streams > i && ofmt_ctx->streams[i] && ofmt_ctx->streams[i]->codec) | ||
| 2080 | + avcodec_close(ofmt_ctx->streams[i]->codec); | ||
| 2081 | + if (filter_ctx && filter_ctx[i].filter_graph) | ||
| 2082 | + avfilter_graph_free(&filter_ctx[i].filter_graph); | ||
| 2083 | + } | ||
| 2084 | + av_free(filter_ctx); | ||
| 2085 | + avformat_close_input(&ifmt_ctx); | ||
| 2086 | + if (ofmt_ctx && !(ofmt_ctx->oformat->flags & AVFMT_NOFILE)) | ||
| 2087 | + avio_closep(&ofmt_ctx->pb); | ||
| 2088 | + avformat_free_context(ofmt_ctx); | ||
| 2089 | + | ||
| 2090 | + //if (ret < 0) | ||
| 2091 | + // av_log(NULL, AV_LOG_ERROR, "Error occurred: %s\n", av_err2str(ret)); | ||
| 2092 | + | ||
| 2093 | + return ret ? 1 : 0; | ||
| 2094 | +} | ||
| 1800 | 2095 |
| @@ -53,10 +53,12 @@ | @@ -53,10 +53,12 @@ | ||
| 53 | <WarningLevel>Level3</WarningLevel> | 53 | <WarningLevel>Level3</WarningLevel> |
| 54 | <Optimization>Disabled</Optimization> | 54 | <Optimization>Disabled</Optimization> |
| 55 | <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> | 55 | <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions> |
| 56 | + <AdditionalIncludeDirectories>..\..\liveAssistant\third-lib\ffmpeg\include</AdditionalIncludeDirectories> | ||
| 56 | </ClCompile> | 57 | </ClCompile> |
| 57 | <Link> | 58 | <Link> |
| 58 | <SubSystem>Console</SubSystem> | 59 | <SubSystem>Console</SubSystem> |
| 59 | <GenerateDebugInformation>true</GenerateDebugInformation> | 60 | <GenerateDebugInformation>true</GenerateDebugInformation> |
| 61 | + <AdditionalLibraryDirectories>..\..\liveAssistant\third-lib\ffmpeg\lib;</AdditionalLibraryDirectories> | ||
| 60 | </Link> | 62 | </Link> |
| 61 | </ItemDefinitionGroup> | 63 | </ItemDefinitionGroup> |
| 62 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> | 64 | <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> |
-
请 注册 或 登录 后发表评论